From 56ffb0deb176d9c84023d2edbb3c9fb06c91a72e Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Mon, 10 Jun 2019 02:29:57 +0200 Subject: [PATCH] Fix code challenge in tidal oauth --- src/core/utilities.cpp | 5 +++++ src/core/utilities.h | 1 + src/tidal/tidalservice.cpp | 41 +++++++++++++++++++++++--------------- src/tidal/tidalservice.h | 3 +++ 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/core/utilities.cpp b/src/core/utilities.cpp index b764fe114..9f0a8f9b5 100644 --- a/src/core/utilities.cpp +++ b/src/core/utilities.cpp @@ -731,6 +731,11 @@ QString GetRandomStringWithCharsAndNumbers(const int len) { return GetRandomString(len, UseCharacters); } +QString CryptographicRandomString(const int len) { + const QString UseCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"); + return GetRandomString(len, UseCharacters); +} + QString GetRandomString(const int len, const QString &UseCharacters) { QString randstr; diff --git a/src/core/utilities.h b/src/core/utilities.h index 794edb1f8..d8bf355b4 100644 --- a/src/core/utilities.h +++ b/src/core/utilities.h @@ -150,6 +150,7 @@ bool IsLaptop(); QString GetRandomStringWithChars(const int len); QString GetRandomStringWithCharsAndNumbers(const int len); +QString CryptographicRandomString(const int len); QString GetRandomString(const int len, const QString &UseCharacters); QString DesktopEnvironment(); diff --git a/src/tidal/tidalservice.cpp b/src/tidal/tidalservice.cpp index 4fedadb45..0760f6798 100644 --- a/src/tidal/tidalservice.cpp +++ b/src/tidal/tidalservice.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ #include "core/network.h" #include "core/database.h" #include "core/song.h" +#include "core/utilities.h" #include "internet/internetsearch.h" #include "collection/collectionbackend.h" #include "collection/collectionmodel.h" @@ -241,14 +243,19 @@ void TidalService::StartAuthorisation() { timer_login_attempt_->setInterval(kTimeResetLoginAttempts); timer_login_attempt_->start(); - const ParamList params = ParamList() - //<< Param("response_type", "token") - << Param("response_type", "code") - << Param("code_challenge", "T36p0vieh1pnvNNsG-0kNNpZIk4ZuP8vna5ZAtooxqo") - << Param("code_challenge_method", "S256") - << Param("redirect_uri", kOAuthRedirectUrl) - << Param("client_id", client_id_) - << Param("scope", "r_usr w_usr"); + code_verifier_ = Utilities::CryptographicRandomString(44); + code_challenge_ = QString(QCryptographicHash::hash(code_verifier_.toUtf8(), QCryptographicHash::Sha256).toBase64(QByteArray::Base64UrlEncoding)); + + if (code_challenge_.lastIndexOf(QChar('=')) == code_challenge_.length() - 1) { + code_challenge_.chop(1); + } + + const ParamList params = ParamList() << Param("response_type", "code") + << Param("code_challenge", code_challenge_) + << Param("code_challenge_method", "S256") + << Param("redirect_uri", kOAuthRedirectUrl) + << Param("client_id", client_id_) + << Param("scope", "r_usr w_usr"); QUrlQuery url_query; for (const Param ¶m : params) { @@ -296,11 +303,11 @@ void TidalService::AuthorisationUrlReceived(const QUrl &url) { QString state = url_query.queryItemValue("state"); const ParamList params = ParamList() << Param("code", code) - << Param("client_id", client_id_) - << Param("grant_type", "authorization_code") - << Param("redirect_uri", kOAuthRedirectUrl) - << Param("scope", "r_usr w_usr") - << Param("code_verifier", "128,113,65,59,36,187,64,14,99,32,149,202,178,5,165,106,14,184,157,42,5,198,243,245,75,115,227,169,183,199,216,67,42,202,105,33,1"); + << Param("client_id", client_id_) + << Param("grant_type", "authorization_code") + << Param("redirect_uri", kOAuthRedirectUrl) + << Param("scope", "r_usr w_usr") + << Param("code_verifier", code_verifier_); QUrlQuery url_query; for (const Param ¶m : params) { @@ -344,9 +351,11 @@ void TidalService::AccessTokenRequestFinished(QNetworkReply *reply) { QString failure_reason; if (json_error.error == QJsonParseError::NoError && !json_doc.isNull() && !json_doc.isEmpty() && json_doc.isObject()) { QJsonObject json_obj = json_doc.object(); - if (!json_obj.isEmpty() && json_obj.contains("redirectUri")) { - QString redirect_uri = json_obj["redirectUri"].toString(); - failure_reason = QString("Authentication failure: %1").arg(redirect_uri); + if (!json_obj.isEmpty() && json_obj.contains("status") && json_obj.contains("userMessage")) { + int status = json_obj["status"].toInt(); + int sub_status = json_obj["subStatus"].toInt(); + QString user_message = json_obj["userMessage"].toString(); + failure_reason = QString("Authentication failure: %1 (%2) (%3)").arg(user_message).arg(status).arg(sub_status); } } if (failure_reason.isEmpty()) { diff --git a/src/tidal/tidalservice.h b/src/tidal/tidalservice.h index 160251c6b..64a829f8c 100644 --- a/src/tidal/tidalservice.h +++ b/src/tidal/tidalservice.h @@ -229,6 +229,9 @@ class TidalService : public InternetService { bool login_sent_; int login_attempts_; + QString code_verifier_; + QString code_challenge_; + QList stream_url_requests_; };