From b5ce69cb4339bdc40e52183aa04609d43a7ca56f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 9 Oct 2019 19:28:46 +0200 Subject: [PATCH] Add Regist with Np-AccountId (Fix #51) --- android/app/src/main/cpp/chiaki-jni.c | 4 +- .../java/com/metallic/chiaki/lib/Chiaki.kt | 2 +- gui/include/registdialog.h | 6 ++- gui/src/registdialog.cpp | 49 ++++++++++++++++--- lib/include/chiaki/regist.h | 19 ++++++- lib/src/regist.c | 44 +++++++++++++---- 6 files changed, 101 insertions(+), 23 deletions(-) diff --git a/android/app/src/main/cpp/chiaki-jni.c b/android/app/src/main/cpp/chiaki-jni.c index 12dbff7..41a4730 100644 --- a/android/app/src/main/cpp/chiaki-jni.c +++ b/android/app/src/main/cpp/chiaki-jni.c @@ -642,13 +642,13 @@ JNIEXPORT void JNICALL JNI_FCN(registStart)(JNIEnv *env, jobject obj, jobject re ChiakiRegistInfo regist_info; regist_info.host = E->GetStringUTFChars(env, host_string, NULL); regist_info.broadcast = broadcast; - regist_info.psn_id = E->GetStringUTFChars(env, psn_id_string, NULL); + // TODO regist_info.psn_id = E->GetStringUTFChars(env, psn_id_string, NULL); regist_info.pin = (uint32_t)pin; err = chiaki_regist_start(®ist->regist, ®ist->log.log, ®ist_info, android_chiaki_regist_cb, regist); E->ReleaseStringUTFChars(env, host_string, regist_info.host); - E->ReleaseStringUTFChars(env, psn_id_string, regist_info.psn_id); + // TODO E->ReleaseStringUTFChars(env, psn_id_string, regist_info.psn_id); if(err != CHIAKI_ERR_SUCCESS) { diff --git a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt index 5dbbac7..c6ef9c4 100644 --- a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt +++ b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt @@ -268,7 +268,7 @@ class DiscoveryService( data class RegistInfo( val host: String, val broadcast: Boolean, - val psnId: String, + val psnId: String, // TODO: this is outdated now val pin: UInt ) diff --git a/gui/include/registdialog.h b/gui/include/registdialog.h index fea4578..d159960 100644 --- a/gui/include/registdialog.h +++ b/gui/include/registdialog.h @@ -30,6 +30,7 @@ class QLineEdit; class QPlainTextEdit; class QDialogButtonBox; class QCheckBox; +class QRadioButton; class RegistDialog : public QDialog { @@ -40,7 +41,10 @@ class RegistDialog : public QDialog QLineEdit *host_edit; QCheckBox *broadcast_check_box; - QLineEdit *psn_id_edit; + QRadioButton *psn_online_id_radio_button; + QLineEdit *psn_online_id_edit; + QRadioButton *psn_account_id_radio_button; + QLineEdit *psn_account_id_edit; QLineEdit *pin_edit; QDialogButtonBox *button_box; QPushButton *register_button; diff --git a/gui/src/registdialog.cpp b/gui/src/registdialog.cpp index 0e7dbb1..07e0844 100644 --- a/gui/src/registdialog.cpp +++ b/gui/src/registdialog.cpp @@ -27,6 +27,7 @@ #include #include #include +#include Q_DECLARE_METATYPE(ChiakiLogLevel) @@ -57,8 +58,23 @@ RegistDialog::RegistDialog(Settings *settings, const QString &host, QWidget *par form_layout->addRow(tr("Broadcast:"), broadcast_check_box); broadcast_check_box->setChecked(host.isEmpty()); - psn_id_edit = new QLineEdit(this); - form_layout->addRow(tr("PSN ID (username, case-sensitive):"), psn_id_edit); + auto UpdatePSNIDEdits = [this]() { + psn_online_id_edit->setEnabled(psn_online_id_radio_button->isChecked()); + psn_account_id_edit->setEnabled(psn_account_id_radio_button->isChecked()); + }; + + psn_online_id_radio_button = new QRadioButton(tr("PSN Online-ID (username, case-sensitive) for PS4 < 7.0:"), this); + psn_online_id_edit = new QLineEdit(this); + form_layout->addRow(psn_online_id_radio_button, psn_online_id_edit); + connect(psn_online_id_radio_button, &QRadioButton::toggled, this, UpdatePSNIDEdits); + + psn_account_id_radio_button = new QRadioButton(tr("PSN Account-ID (base64) for PS4 >= 7.0:"), this); + psn_account_id_edit = new QLineEdit(this); + form_layout->addRow(psn_account_id_radio_button, psn_account_id_edit); + psn_account_id_radio_button->setChecked(true); + connect(psn_account_id_radio_button, &QRadioButton::toggled, this, UpdatePSNIDEdits); + + UpdatePSNIDEdits(); pin_edit = new QLineEdit(this); pin_edit->setValidator(new QRegularExpressionValidator(pin_re, pin_edit)); @@ -71,7 +87,7 @@ RegistDialog::RegistDialog(Settings *settings, const QString &host, QWidget *par connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(host_edit, &QLineEdit::textChanged, this, &RegistDialog::ValidateInput); - connect(psn_id_edit, &QLineEdit::textChanged, this, &RegistDialog::ValidateInput); + connect(psn_online_id_edit, &QLineEdit::textChanged, this, &RegistDialog::ValidateInput); connect(pin_edit, &QLineEdit::textChanged, this, &RegistDialog::ValidateInput); ValidateInput(); } @@ -83,7 +99,8 @@ RegistDialog::~RegistDialog() void RegistDialog::ValidateInput() { bool valid = !host_edit->text().trimmed().isEmpty() - && !psn_id_edit->text().trimmed().isEmpty() + && (!psn_online_id_radio_button->isChecked() || !psn_online_id_edit->text().trimmed().isEmpty()) + && (!psn_account_id_radio_button->isChecked() || !psn_account_id_radio_button->text().trimmed().isEmpty()) && pin_edit->text().length() == PIN_LENGTH; register_button->setEnabled(valid); } @@ -91,10 +108,28 @@ void RegistDialog::ValidateInput() void RegistDialog::accept() { ChiakiRegistInfo info = {}; - QByteArray psn_id = psn_id_edit->text().trimmed().toUtf8(); QByteArray host = host_edit->text().trimmed().toUtf8(); - info.psn_id = psn_id.data(); - info.host = host.data(); + info.host = host.constData(); + + QByteArray psn_id; // keep this out of the if scope + if(psn_online_id_radio_button->isChecked()) + { + psn_id = psn_online_id_edit->text().trimmed().toUtf8(); + info.psn_online_id = psn_id.constData(); + } + else + { + QString account_id_b64 = psn_account_id_edit->text().trimmed(); + QByteArray account_id = QByteArray::fromBase64(account_id_b64.toUtf8()); + if(account_id.size() != CHIAKI_PSN_ACCOUNT_ID_SIZE) + { + QMessageBox::critical(this, tr("Invalid Account-ID"), tr("The PSN Account-ID must be exactly %1 bytes encoded as base64.").arg(CHIAKI_PSN_ACCOUNT_ID_SIZE)); + return; + } + info.psn_online_id = nullptr; + memcpy(info.psn_account_id, account_id.constData(), CHIAKI_PSN_ACCOUNT_ID_SIZE); + } + info.broadcast = broadcast_check_box->isChecked(); info.pin = (uint32_t)pin_edit->text().toULong(); diff --git a/lib/include/chiaki/regist.h b/lib/include/chiaki/regist.h index 1c8fb72..6140967 100644 --- a/lib/include/chiaki/regist.h +++ b/lib/include/chiaki/regist.h @@ -29,11 +29,23 @@ extern "C" { #endif +#define CHIAKI_PSN_ACCOUNT_ID_SIZE 8 + typedef struct chiaki_regist_info_t { const char *host; bool broadcast; - const char *psn_id; + + /** + * may be null, in which case psn_account_id will be used + */ + const char *psn_online_id; + + /** + * will be used if psn_online_id is null, for PS4 >= 7.0 + */ + uint8_t psn_account_id[CHIAKI_PSN_ACCOUNT_ID_SIZE]; + uint32_t pin; } ChiakiRegistInfo; @@ -79,7 +91,10 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_start(ChiakiRegist *regist, ChiakiLo CHIAKI_EXPORT void chiaki_regist_fini(ChiakiRegist *regist); CHIAKI_EXPORT void chiaki_regist_stop(ChiakiRegist *regist); -CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_request_payload_format(uint8_t *buf, size_t *buf_size, ChiakiRPCrypt *crypt, const char *psn_id); +/** + * @param psn_account_id must be exactly of size CHIAKI_PSN_ACCOUNT_ID_SIZE + */ +CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_request_payload_format(uint8_t *buf, size_t *buf_size, ChiakiRPCrypt *crypt, const char *psn_online_id, const uint8_t *psn_account_id); #ifdef __cplusplus } diff --git a/lib/src/regist.c b/lib/src/regist.c index 56be300..2bed5c2 100644 --- a/lib/src/regist.c +++ b/lib/src/regist.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -55,9 +56,13 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_start(ChiakiRegist *regist, ChiakiLo regist->info.host = strdup(regist->info.host); if(!regist->info.host) return CHIAKI_ERR_MEMORY; - regist->info.psn_id = strdup(regist->info.psn_id); - if(!regist->info.psn_id) - goto error_host; + + if(regist->info.psn_online_id) + { + regist->info.psn_online_id = strdup(regist->info.psn_online_id); + if(!regist->info.psn_online_id) + goto error_host; + } regist->cb = cb; regist->cb_user = cb_user; @@ -75,7 +80,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_start(ChiakiRegist *regist, ChiakiLo error_stop_pipe: chiaki_stop_pipe_fini(®ist->stop_pipe); error_psn_id: - free((char *)regist->info.psn_id); + free((char *)regist->info.psn_online_id); error_host: free((char *)regist->info.host); return err; @@ -85,7 +90,7 @@ CHIAKI_EXPORT void chiaki_regist_fini(ChiakiRegist *regist) { chiaki_thread_join(®ist->thread, NULL); chiaki_stop_pipe_fini(®ist->stop_pipe); - free((char *)regist->info.psn_id); + free((char *)regist->info.psn_online_id); free((char *)regist->info.host); } @@ -106,13 +111,20 @@ static const char * const request_fmt = "HOST: 10.0.2.15\r\n" // random lol "User-Agent: remoteplay Windows\r\n" "Connection: close\r\n" - "Content-Length: %llu\r\n\r\n"; + "Content-Length: %llu\r\n" + "RP-Version: " CHIAKI_RP_CLIENT_VERSION "\r\n\r\n"; -static const char * const request_inner_fmt = +static const char * const request_inner_account_id_fmt = + "Client-Type: Windows\r\n" + "Np-AccountId: %s\r\n"; + +static const char * const request_inner_online_id_fmt = "Client-Type: Windows\r\n" "Np-Online-Id: %s\r\n"; -CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_request_payload_format(uint8_t *buf, size_t *buf_size, ChiakiRPCrypt *crypt, const char *psn_id) + + +CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_request_payload_format(uint8_t *buf, size_t *buf_size, ChiakiRPCrypt *crypt, const char *psn_online_id, const uint8_t *psn_account_id) { size_t buf_size_val = *buf_size; static const size_t inner_header_off = 0x1e0; @@ -120,7 +132,19 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_request_payload_format(uint8_t *buf, return CHIAKI_ERR_BUF_TOO_SMALL; memset(buf, 'A', inner_header_off); chiaki_rpcrypt_aeropause(buf + 0x11c, crypt->ambassador); - int inner_header_size = snprintf((char *)buf + inner_header_off, buf_size_val - inner_header_off, request_inner_fmt, psn_id); + int inner_header_size; + if(psn_online_id) + inner_header_size = snprintf((char *)buf + inner_header_off, buf_size_val - inner_header_off, request_inner_online_id_fmt, psn_online_id); + else if(psn_account_id) + { + char account_id_b64[CHIAKI_PSN_ACCOUNT_ID_SIZE * 2]; + ChiakiErrorCode err = chiaki_base64_encode(psn_account_id, CHIAKI_PSN_ACCOUNT_ID_SIZE, account_id_b64, sizeof(account_id_b64)); + if(err != CHIAKI_ERR_SUCCESS) + return err; + inner_header_size = snprintf((char *)buf + inner_header_off, buf_size_val - inner_header_off, request_inner_account_id_fmt, account_id_b64); + } + else + return CHIAKI_ERR_INVALID_DATA; if(inner_header_size < 0 || inner_header_size >= buf_size_val - inner_header_off) return CHIAKI_ERR_BUF_TOO_SMALL; ChiakiErrorCode err = chiaki_rpcrypt_encrypt(crypt, 0, buf + inner_header_off, buf + inner_header_off, inner_header_size); @@ -148,7 +172,7 @@ static void *regist_thread_func(void *user) uint8_t payload[0x400]; size_t payload_size = sizeof(payload); - err = chiaki_regist_request_payload_format(payload, &payload_size, &crypt, regist->info.psn_id); + err = chiaki_regist_request_payload_format(payload, &payload_size, &crypt, regist->info.psn_online_id, regist->info.psn_account_id); if(err != CHIAKI_ERR_SUCCESS) { CHIAKI_LOGE(regist->log, "Regist failed to format payload");