From 75ac9a29d3a4d969e93ae1d625cab4ce3e37c7cb Mon Sep 17 00:00:00 2001 From: PatTheMav Date: Wed, 4 Dec 2024 18:44:42 +0100 Subject: [PATCH] frontend: Split OAuth implementation into single files per C++ class --- frontend/dialogs/OAuthLogin.cpp | 232 +-------------------- frontend/dialogs/OAuthLogin.hpp | 54 ----- frontend/docks/YouTubeChatDock.cpp | 324 +---------------------------- frontend/docks/YouTubeChatDock.hpp | 43 +--- frontend/oauth/OAuth.cpp | 118 +---------- frontend/oauth/OAuth.hpp | 31 +-- frontend/oauth/YoutubeAuth.cpp | 64 ++---- frontend/oauth/YoutubeAuth.hpp | 33 +-- 8 files changed, 42 insertions(+), 857 deletions(-) diff --git a/frontend/dialogs/OAuthLogin.cpp b/frontend/dialogs/OAuthLogin.cpp index 04458c9c5..64af6869b 100644 --- a/frontend/dialogs/OAuthLogin.cpp +++ b/frontend/dialogs/OAuthLogin.cpp @@ -1,31 +1,19 @@ -#include "moc_auth-oauth.cpp" +#include "OAuthLogin.hpp" -#include -#include -#include - -#include -#include - -#include "window-basic-main.hpp" -#include "remote-text.hpp" - -#include - -#include - -#include "ui-config.h" - -using namespace json11; +#include #ifdef BROWSER_AVAILABLE #include +#endif +#include + +#include "moc_OAuthLogin.cpp" + +#ifdef BROWSER_AVAILABLE extern QCef *cef; extern QCefCookieManager *panel_cookies; #endif -/* ------------------------------------------------------------------------- */ - OAuthLogin::OAuthLogin(QWidget *parent, const std::string &url, bool token) : QDialog(parent), get_token(token) { #ifdef BROWSER_AVAILABLE @@ -116,207 +104,3 @@ void OAuthLogin::urlChanged(const QString &url) accept(); } - -/* ------------------------------------------------------------------------- */ - -struct OAuthInfo { - Auth::Def def; - OAuth::login_cb login; - OAuth::delete_cookies_cb delete_cookies; -}; - -static std::vector loginCBs; - -void OAuth::RegisterOAuth(const Def &d, create_cb create, login_cb login, delete_cookies_cb delete_cookies) -{ - OAuthInfo info = {d, login, delete_cookies}; - loginCBs.push_back(info); - RegisterAuth(d, create); -} - -std::shared_ptr OAuth::Login(QWidget *parent, const std::string &service) -{ - for (auto &a : loginCBs) { - if (service.find(a.def.service) != std::string::npos) { - return a.login(parent, service); - } - } - - return nullptr; -} - -void OAuth::DeleteCookies(const std::string &service) -{ - for (auto &a : loginCBs) { - if (service.find(a.def.service) != std::string::npos) { - a.delete_cookies(); - } - } -} - -void OAuth::SaveInternal() -{ - OBSBasic *main = OBSBasic::Get(); - config_set_string(main->Config(), service(), "RefreshToken", refresh_token.c_str()); - config_set_string(main->Config(), service(), "Token", token.c_str()); - config_set_uint(main->Config(), service(), "ExpireTime", expire_time); - config_set_int(main->Config(), service(), "ScopeVer", currentScopeVer); -} - -static inline std::string get_config_str(OBSBasic *main, const char *section, const char *name) -{ - const char *val = config_get_string(main->Config(), section, name); - return val ? val : ""; -} - -bool OAuth::LoadInternal() -{ - OBSBasic *main = OBSBasic::Get(); - refresh_token = get_config_str(main, service(), "RefreshToken"); - token = get_config_str(main, service(), "Token"); - expire_time = config_get_uint(main->Config(), service(), "ExpireTime"); - currentScopeVer = (int)config_get_int(main->Config(), service(), "ScopeVer"); - return implicit ? !token.empty() : !refresh_token.empty(); -} - -bool OAuth::TokenExpired() -{ - if (token.empty()) - return true; - if ((uint64_t)time(nullptr) > expire_time - 5) - return true; - return false; -} - -bool OAuth::GetToken(const char *url, const std::string &client_id, const std::string &secret, - const std::string &redirect_uri, int scope_ver, const std::string &auth_code, bool retry) -{ - return GetTokenInternal(url, client_id, secret, redirect_uri, scope_ver, auth_code, retry); -} - -bool OAuth::GetToken(const char *url, const std::string &client_id, int scope_ver, const std::string &auth_code, - bool retry) -{ - return GetTokenInternal(url, client_id, {}, {}, scope_ver, auth_code, retry); -} - -bool OAuth::GetTokenInternal(const char *url, const std::string &client_id, const std::string &secret, - const std::string &redirect_uri, int scope_ver, const std::string &auth_code, bool retry) -try { - std::string output; - std::string error; - std::string desc; - - if (currentScopeVer > 0 && currentScopeVer < scope_ver) { - if (RetryLogin()) { - return true; - } else { - QString title = QTStr("Auth.InvalidScope.Title"); - QString text = QTStr("Auth.InvalidScope.Text").arg(service()); - - QMessageBox::warning(OBSBasic::Get(), title, text); - } - } - - if (auth_code.empty() && !TokenExpired()) { - return true; - } - - std::string post_data; - post_data += "action=redirect&client_id="; - post_data += client_id; - if (!secret.empty()) { - post_data += "&client_secret="; - post_data += secret; - } - if (!redirect_uri.empty()) { - post_data += "&redirect_uri="; - post_data += redirect_uri; - } - - if (!auth_code.empty()) { - post_data += "&grant_type=authorization_code&code="; - post_data += auth_code; - } else { - post_data += "&grant_type=refresh_token&refresh_token="; - post_data += refresh_token; - } - - bool success = false; - - auto func = [&]() { - success = GetRemoteFile(url, output, error, nullptr, "application/x-www-form-urlencoded", "", - post_data.c_str(), std::vector(), nullptr, 5); - }; - - ExecThreadedWithoutBlocking(func, QTStr("Auth.Authing.Title"), QTStr("Auth.Authing.Text").arg(service())); - if (!success || output.empty()) - throw ErrorInfo("Failed to get token from remote", error); - - Json json = Json::parse(output, error); - if (!error.empty()) - throw ErrorInfo("Failed to parse json", error); - - /* -------------------------- */ - /* error handling */ - - error = json["error"].string_value(); - if (!retry && error == "invalid_grant") { - if (RetryLogin()) { - return true; - } - } - if (!error.empty()) - throw ErrorInfo(error, json["error_description"].string_value()); - - /* -------------------------- */ - /* success! */ - - expire_time = (uint64_t)time(nullptr) + json["expires_in"].int_value(); - token = json["access_token"].string_value(); - if (token.empty()) - throw ErrorInfo("Failed to get token from remote", error); - - if (!auth_code.empty()) { - refresh_token = json["refresh_token"].string_value(); - if (refresh_token.empty()) - throw ErrorInfo("Failed to get refresh token from " - "remote", - error); - - currentScopeVer = scope_ver; - } - - return true; - -} catch (ErrorInfo &info) { - if (!retry) { - QString title = QTStr("Auth.AuthFailure.Title"); - QString text = QTStr("Auth.AuthFailure.Text").arg(service(), info.message.c_str(), info.error.c_str()); - - QMessageBox::warning(OBSBasic::Get(), title, text); - } - - blog(LOG_WARNING, "%s: %s: %s", __FUNCTION__, info.message.c_str(), info.error.c_str()); - return false; -} - -void OAuthStreamKey::OnStreamConfig() -{ - if (key_.empty()) - return; - - OBSBasic *main = OBSBasic::Get(); - obs_service_t *service = main->GetService(); - - OBSDataAutoRelease settings = obs_service_get_settings(service); - - bool bwtest = obs_data_get_bool(settings, "bwtest"); - - if (bwtest && strcmp(this->service(), "Twitch") == 0) - obs_data_set_string(settings, "key", (key_ + "?bandwidthtest=true").c_str()); - else - obs_data_set_string(settings, "key", key_.c_str()); - - obs_service_update(service, settings); -} diff --git a/frontend/dialogs/OAuthLogin.hpp b/frontend/dialogs/OAuthLogin.hpp index b6602e815..9e6e94b49 100644 --- a/frontend/dialogs/OAuthLogin.hpp +++ b/frontend/dialogs/OAuthLogin.hpp @@ -1,10 +1,6 @@ #pragma once #include -#include -#include - -#include "auth-base.hpp" class QCefWidget; @@ -30,53 +26,3 @@ public: public slots: void urlChanged(const QString &url); }; - -class OAuth : public Auth { - Q_OBJECT - -public: - inline OAuth(const Def &d) : Auth(d) {} - - typedef std::function(QWidget *, const std::string &service_name)> login_cb; - typedef std::function delete_cookies_cb; - - static std::shared_ptr Login(QWidget *parent, const std::string &service); - static void DeleteCookies(const std::string &service); - - static void RegisterOAuth(const Def &d, create_cb create, login_cb login, delete_cookies_cb delete_cookies); - -protected: - std::string refresh_token; - std::string token; - bool implicit = false; - uint64_t expire_time = 0; - int currentScopeVer = 0; - - virtual void SaveInternal() override; - virtual bool LoadInternal() override; - - virtual bool RetryLogin() = 0; - bool TokenExpired(); - bool GetToken(const char *url, const std::string &client_id, int scope_ver, - const std::string &auth_code = std::string(), bool retry = false); - bool GetToken(const char *url, const std::string &client_id, const std::string &secret, - const std::string &redirect_uri, int scope_ver, const std::string &auth_code, bool retry); - -private: - bool GetTokenInternal(const char *url, const std::string &client_id, const std::string &secret, - const std::string &redirect_uri, int scope_ver, const std::string &auth_code, bool retry); -}; - -class OAuthStreamKey : public OAuth { - Q_OBJECT - -protected: - std::string key_; - -public: - inline OAuthStreamKey(const Def &d) : OAuth(d) {} - - inline const std::string &key() const { return key_; } - - virtual void OnStreamConfig() override; -}; diff --git a/frontend/docks/YouTubeChatDock.cpp b/frontend/docks/YouTubeChatDock.cpp index 714003145..eae3a2b7c 100644 --- a/frontend/docks/YouTubeChatDock.cpp +++ b/frontend/docks/YouTubeChatDock.cpp @@ -1,323 +1,15 @@ -#include "moc_auth-youtube.cpp" +#include "YouTubeChatDock.hpp" + +#include +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#ifdef WIN32 -#include -#include +#include +#include -#pragma comment(lib, "shell32") -#endif - -#include "auth-listener.hpp" -#include "obs-app.hpp" -#include "ui-config.h" -#include "youtube-api-wrappers.hpp" -#include "window-basic-main.hpp" -#include "obf.h" - -#ifdef BROWSER_AVAILABLE -#include "window-dock-browser.hpp" -#endif - -using namespace json11; - -/* ------------------------------------------------------------------------- */ -#define YOUTUBE_AUTH_URL "https://accounts.google.com/o/oauth2/v2/auth" -#define YOUTUBE_TOKEN_URL "https://www.googleapis.com/oauth2/v4/token" -#define YOUTUBE_SCOPE_VERSION 1 -#define YOUTUBE_API_STATE_LENGTH 32 -#define SECTION_NAME "YouTube" - -#define YOUTUBE_CHAT_PLACEHOLDER_URL "https://obsproject.com/placeholders/youtube-chat" -#define YOUTUBE_CHAT_POPOUT_URL "https://www.youtube.com/live_chat?is_popout=1&dark_theme=1&v=%1" - -#define YOUTUBE_CHAT_DOCK_NAME "ytChat" - -static const char allowedChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; -static const int allowedCount = static_cast(sizeof(allowedChars) - 1); -/* ------------------------------------------------------------------------- */ - -static inline void OpenBrowser(const QString auth_uri) -{ - QUrl url(auth_uri, QUrl::StrictMode); - QDesktopServices::openUrl(url); -} - -static void DeleteCookies() -{ - if (panel_cookies) { - panel_cookies->DeleteCookies("youtube.com", ""); - panel_cookies->DeleteCookies("google.com", ""); - } -} - -void RegisterYoutubeAuth() -{ - for (auto &service : youtubeServices) { - OAuth::RegisterOAuth( - service, [service]() { return std::make_shared(service); }, - YoutubeAuth::Login, DeleteCookies); - } -} - -YoutubeAuth::YoutubeAuth(const Def &d) : OAuthStreamKey(d), section(SECTION_NAME) {} - -YoutubeAuth::~YoutubeAuth() -{ - if (!uiLoaded) - return; - -#ifdef BROWSER_AVAILABLE - OBSBasic *main = OBSBasic::Get(); - - main->RemoveDockWidget(YOUTUBE_CHAT_DOCK_NAME); - chat = nullptr; -#endif -} - -bool YoutubeAuth::RetryLogin() -{ - return true; -} - -void YoutubeAuth::SaveInternal() -{ - OBSBasic *main = OBSBasic::Get(); - config_set_string(main->Config(), service(), "DockState", main->saveState().toBase64().constData()); - - const char *section_name = section.c_str(); - config_set_string(main->Config(), section_name, "RefreshToken", refresh_token.c_str()); - config_set_string(main->Config(), section_name, "Token", token.c_str()); - config_set_uint(main->Config(), section_name, "ExpireTime", expire_time); - config_set_int(main->Config(), section_name, "ScopeVer", currentScopeVer); -} - -static inline std::string get_config_str(OBSBasic *main, const char *section, const char *name) -{ - const char *val = config_get_string(main->Config(), section, name); - return val ? val : ""; -} - -bool YoutubeAuth::LoadInternal() -{ - OBSBasic *main = OBSBasic::Get(); - - const char *section_name = section.c_str(); - refresh_token = get_config_str(main, section_name, "RefreshToken"); - token = get_config_str(main, section_name, "Token"); - expire_time = config_get_uint(main->Config(), section_name, "ExpireTime"); - currentScopeVer = (int)config_get_int(main->Config(), section_name, "ScopeVer"); - firstLoad = false; - return implicit ? !token.empty() : !refresh_token.empty(); -} - -void YoutubeAuth::LoadUI() -{ - if (uiLoaded) - return; - -#ifdef BROWSER_AVAILABLE - if (!cef) - return; - - OBSBasic::InitBrowserPanelSafeBlock(); - OBSBasic *main = OBSBasic::Get(); - - QCefWidget *browser; - - QSize size = main->frameSize(); - QPoint pos = main->pos(); - - chat = new YoutubeChatDock(QTStr("Auth.Chat")); - chat->setObjectName(YOUTUBE_CHAT_DOCK_NAME); - chat->resize(300, 600); - chat->setMinimumSize(200, 300); - chat->setAllowedAreas(Qt::AllDockWidgetAreas); - - browser = cef->create_widget(chat, YOUTUBE_CHAT_PLACEHOLDER_URL, panel_cookies); - - chat->SetWidget(browser); - main->AddDockWidget(chat, Qt::RightDockWidgetArea); - - chat->setFloating(true); - chat->move(pos.x() + size.width() - chat->width() - 50, pos.y() + 50); - - if (firstLoad) { - chat->setVisible(true); - } -#endif - - main->NewYouTubeAppDock(); - - if (!firstLoad) { - const char *dockStateStr = config_get_string(main->Config(), service(), "DockState"); - QByteArray dockState = QByteArray::fromBase64(QByteArray(dockStateStr)); - - if (main->isVisible() || !main->isMaximized()) - main->restoreState(dockState); - } - - uiLoaded = true; -} - -void YoutubeAuth::SetChatId(const QString &chat_id) -{ -#ifdef BROWSER_AVAILABLE - QString chat_url = QString(YOUTUBE_CHAT_POPOUT_URL).arg(chat_id); - - if (chat && chat->cefWidget) { - chat->cefWidget->setURL(chat_url.toStdString()); - } -#else - UNUSED_PARAMETER(chat_id); -#endif -} - -void YoutubeAuth::ResetChat() -{ -#ifdef BROWSER_AVAILABLE - if (chat && chat->cefWidget) { - chat->cefWidget->setURL(YOUTUBE_CHAT_PLACEHOLDER_URL); - } -#endif -} - -void YoutubeAuth::ReloadChat() -{ -#ifdef BROWSER_AVAILABLE - if (chat && chat->cefWidget) { - chat->cefWidget->reloadPage(); - } -#endif -} - -QString YoutubeAuth::GenerateState() -{ - char state[YOUTUBE_API_STATE_LENGTH + 1]; - QRandomGenerator *rng = QRandomGenerator::system(); - int i; - - for (i = 0; i < YOUTUBE_API_STATE_LENGTH; i++) - state[i] = allowedChars[rng->bounded(0, allowedCount)]; - state[i] = 0; - - return state; -} - -// Static. -std::shared_ptr YoutubeAuth::Login(QWidget *owner, const std::string &service) -{ - QString auth_code; - AuthListener server; - - auto it = std::find_if(youtubeServices.begin(), youtubeServices.end(), - [service](auto &item) { return service == item.service; }); - if (it == youtubeServices.end()) { - return nullptr; - } - const auto auth = std::make_shared(*it); - - QString redirect_uri = QString("http://127.0.0.1:%1").arg(server.GetPort()); - - QMessageBox dlg(owner); - dlg.setWindowFlags(dlg.windowFlags() & ~Qt::WindowCloseButtonHint); - dlg.setWindowTitle(QTStr("YouTube.Auth.WaitingAuth.Title")); - - std::string clientid = YOUTUBE_CLIENTID; - std::string secret = YOUTUBE_SECRET; - deobfuscate_str(&clientid[0], YOUTUBE_CLIENTID_HASH); - deobfuscate_str(&secret[0], YOUTUBE_SECRET_HASH); - - QString state; - state = auth->GenerateState(); - server.SetState(state); - - QString url_template; - url_template += "%1"; - url_template += "?response_type=code"; - url_template += "&client_id=%2"; - url_template += "&redirect_uri=%3"; - url_template += "&state=%4"; - url_template += "&scope=https://www.googleapis.com/auth/youtube"; - QString url = url_template.arg(YOUTUBE_AUTH_URL, clientid.c_str(), redirect_uri, state); - - QString text = QTStr("YouTube.Auth.WaitingAuth.Text"); - text = text.arg(QString("Google OAuth Service").arg(url)); - - dlg.setText(text); - dlg.setTextFormat(Qt::RichText); - dlg.setStandardButtons(QMessageBox::StandardButton::Cancel); -#if defined(__APPLE__) && QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) - /* We can't show clickable links with the native NSAlert, so let's - * force the old non-native dialog instead. */ - dlg.setOption(QMessageBox::Option::DontUseNativeDialog); -#endif - - connect(&dlg, &QMessageBox::buttonClicked, &dlg, [&](QAbstractButton *) { -#ifdef _DEBUG - blog(LOG_DEBUG, "Action Cancelled."); -#endif - // TODO: Stop server. - dlg.reject(); - }); - - // Async Login. - connect(&server, &AuthListener::ok, &dlg, [&dlg, &auth_code](QString code) { -#ifdef _DEBUG - blog(LOG_DEBUG, "Got youtube redirected answer: %s", QT_TO_UTF8(code)); -#endif - auth_code = code; - dlg.accept(); - }); - connect(&server, &AuthListener::fail, &dlg, [&dlg]() { -#ifdef _DEBUG - blog(LOG_DEBUG, "No access granted"); -#endif - dlg.reject(); - }); - - auto open_external_browser = [url]() { - OpenBrowser(url); - }; - QScopedPointer thread(CreateQThread(open_external_browser)); - thread->start(); - -#if defined(__APPLE__) && QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) && QT_VERSION < QT_VERSION_CHECK(6, 6, 0) - const bool nativeDialogs = qApp->testAttribute(Qt::AA_DontUseNativeDialogs); - App()->setAttribute(Qt::AA_DontUseNativeDialogs, true); - dlg.exec(); - App()->setAttribute(Qt::AA_DontUseNativeDialogs, nativeDialogs); -#else - dlg.exec(); -#endif - - if (dlg.result() == QMessageBox::Cancel || dlg.result() == QDialog::Rejected) - return nullptr; - - if (!auth->GetToken(YOUTUBE_TOKEN_URL, clientid, secret, QT_TO_UTF8(redirect_uri), YOUTUBE_SCOPE_VERSION, - QT_TO_UTF8(auth_code), true)) { - return nullptr; - } - - config_t *config = OBSBasic::Get()->Config(); - config_remove_value(config, "YouTube", "ChannelName"); - - ChannelDescription cd; - if (auth->GetChannelDescription(cd)) - config_set_string(config, "YouTube", "ChannelName", QT_TO_UTF8(cd.title)); - - config_save_safe(config, "tmp", nullptr); - return auth; -} +#include "moc_YouTubeChatDock.cpp" #ifdef BROWSER_AVAILABLE void YoutubeChatDock::YoutubeCookieCheck() diff --git a/frontend/docks/YouTubeChatDock.hpp b/frontend/docks/YouTubeChatDock.hpp index cd560db7d..034be0e67 100644 --- a/frontend/docks/YouTubeChatDock.hpp +++ b/frontend/docks/YouTubeChatDock.hpp @@ -1,15 +1,8 @@ #pragma once -#include -#include -#include -#include - -#include "auth-oauth.hpp" - #ifdef BROWSER_AVAILABLE -#include "window-dock-browser.hpp" -#include +#include "BrowserDock.hpp" + class YoutubeChatDock : public BrowserDock { Q_OBJECT @@ -28,35 +21,3 @@ private slots: void YoutubeCookieCheck(); }; #endif - -inline const std::vector youtubeServices = {{"YouTube - RTMP", Auth::Type::OAuth_LinkedAccount, true, true}, - {"YouTube - RTMPS", Auth::Type::OAuth_LinkedAccount, true, true}, - {"YouTube - HLS", Auth::Type::OAuth_LinkedAccount, true, true}}; - -class YoutubeAuth : public OAuthStreamKey { - Q_OBJECT - - bool uiLoaded = false; - std::string section; - -#ifdef BROWSER_AVAILABLE - YoutubeChatDock *chat = nullptr; -#endif - - virtual bool RetryLogin() override; - virtual void SaveInternal() override; - virtual bool LoadInternal() override; - virtual void LoadUI() override; - - QString GenerateState(); - -public: - YoutubeAuth(const Def &d); - ~YoutubeAuth(); - - void SetChatId(const QString &chat_id); - void ResetChat(); - void ReloadChat(); - - static std::shared_ptr Login(QWidget *parent, const std::string &service); -}; diff --git a/frontend/oauth/OAuth.cpp b/frontend/oauth/OAuth.cpp index 04458c9c5..a7d6f60d6 100644 --- a/frontend/oauth/OAuth.cpp +++ b/frontend/oauth/OAuth.cpp @@ -1,124 +1,17 @@ -#include "moc_auth-oauth.cpp" +#include "OAuth.hpp" -#include -#include -#include +#include +#include #include -#include - -#include "window-basic-main.hpp" -#include "remote-text.hpp" - -#include +#include #include -#include "ui-config.h" +#include "moc_OAuth.cpp" using namespace json11; -#ifdef BROWSER_AVAILABLE -#include -extern QCef *cef; -extern QCefCookieManager *panel_cookies; -#endif - -/* ------------------------------------------------------------------------- */ - -OAuthLogin::OAuthLogin(QWidget *parent, const std::string &url, bool token) : QDialog(parent), get_token(token) -{ -#ifdef BROWSER_AVAILABLE - if (!cef) { - return; - } - - setWindowTitle("Auth"); - setMinimumSize(400, 400); - resize(700, 700); - - Qt::WindowFlags flags = windowFlags(); - Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint; - setWindowFlags(flags & (~helpFlag)); - - OBSBasic::InitBrowserPanelSafeBlock(); - - cefWidget = cef->create_widget(nullptr, url, panel_cookies); - if (!cefWidget) { - fail = true; - return; - } - - connect(cefWidget, &QCefWidget::titleChanged, this, &OAuthLogin::setWindowTitle); - connect(cefWidget, &QCefWidget::urlChanged, this, &OAuthLogin::urlChanged); - - QPushButton *close = new QPushButton(QTStr("Cancel")); - connect(close, &QAbstractButton::clicked, this, &QDialog::reject); - - QHBoxLayout *bottomLayout = new QHBoxLayout(); - bottomLayout->addStretch(); - bottomLayout->addWidget(close); - bottomLayout->addStretch(); - - QVBoxLayout *topLayout = new QVBoxLayout(this); - topLayout->addWidget(cefWidget); - topLayout->addLayout(bottomLayout); -#else - UNUSED_PARAMETER(url); -#endif -} - -OAuthLogin::~OAuthLogin() {} - -int OAuthLogin::exec() -{ -#ifdef BROWSER_AVAILABLE - if (cefWidget) { - return QDialog::exec(); - } -#endif - return QDialog::Rejected; -} - -void OAuthLogin::reject() -{ -#ifdef BROWSER_AVAILABLE - delete cefWidget; -#endif - QDialog::reject(); -} - -void OAuthLogin::accept() -{ -#ifdef BROWSER_AVAILABLE - delete cefWidget; -#endif - QDialog::accept(); -} - -void OAuthLogin::urlChanged(const QString &url) -{ - std::string uri = get_token ? "access_token=" : "code="; - int code_idx = url.indexOf(uri.c_str()); - if (code_idx == -1) - return; - - if (!url.startsWith(OAUTH_BASE_URL)) - return; - - code_idx += (int)uri.size(); - - int next_idx = url.indexOf("&", code_idx); - if (next_idx != -1) - code = url.mid(code_idx, next_idx - code_idx); - else - code = url.right(url.size() - code_idx); - - accept(); -} - -/* ------------------------------------------------------------------------- */ - struct OAuthInfo { Auth::Def def; OAuth::login_cb login; @@ -126,7 +19,6 @@ struct OAuthInfo { }; static std::vector loginCBs; - void OAuth::RegisterOAuth(const Def &d, create_cb create, login_cb login, delete_cookies_cb delete_cookies) { OAuthInfo info = {d, login, delete_cookies}; diff --git a/frontend/oauth/OAuth.hpp b/frontend/oauth/OAuth.hpp index b6602e815..46bd720ca 100644 --- a/frontend/oauth/OAuth.hpp +++ b/frontend/oauth/OAuth.hpp @@ -1,35 +1,6 @@ #pragma once -#include -#include -#include - -#include "auth-base.hpp" - -class QCefWidget; - -class OAuthLogin : public QDialog { - Q_OBJECT - - QCefWidget *cefWidget = nullptr; - QString code; - bool get_token = false; - bool fail = false; - -public: - OAuthLogin(QWidget *parent, const std::string &url, bool token); - ~OAuthLogin(); - - inline QString GetCode() const { return code; } - inline bool LoadFail() const { return fail; } - - virtual int exec() override; - virtual void reject() override; - virtual void accept() override; - -public slots: - void urlChanged(const QString &url); -}; +#include "Auth.hpp" class OAuth : public Auth { Q_OBJECT diff --git a/frontend/oauth/YoutubeAuth.cpp b/frontend/oauth/YoutubeAuth.cpp index 714003145..9d626bb7e 100644 --- a/frontend/oauth/YoutubeAuth.cpp +++ b/frontend/oauth/YoutubeAuth.cpp @@ -1,36 +1,21 @@ -#include "moc_auth-youtube.cpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef WIN32 -#include -#include - -#pragma comment(lib, "shell32") -#endif - -#include "auth-listener.hpp" -#include "obs-app.hpp" -#include "ui-config.h" -#include "youtube-api-wrappers.hpp" -#include "window-basic-main.hpp" -#include "obf.h" +#include "YoutubeAuth.hpp" #ifdef BROWSER_AVAILABLE -#include "window-dock-browser.hpp" +#include #endif +#include +#include +#include +#include -using namespace json11; +#include +#include + +#include +#include + +#include "moc_YoutubeAuth.cpp" -/* ------------------------------------------------------------------------- */ #define YOUTUBE_AUTH_URL "https://accounts.google.com/o/oauth2/v2/auth" #define YOUTUBE_TOKEN_URL "https://www.googleapis.com/oauth2/v4/token" #define YOUTUBE_SCOPE_VERSION 1 @@ -318,26 +303,3 @@ std::shared_ptr YoutubeAuth::Login(QWidget *owner, const std::string &serv config_save_safe(config, "tmp", nullptr); return auth; } - -#ifdef BROWSER_AVAILABLE -void YoutubeChatDock::YoutubeCookieCheck() -{ - QPointer this_ = this; - auto cb = [this_](bool currentlyLoggedIn) { - bool previouslyLoggedIn = this_->isLoggedIn; - this_->isLoggedIn = currentlyLoggedIn; - bool loginStateChanged = (currentlyLoggedIn && !previouslyLoggedIn) || - (!currentlyLoggedIn && previouslyLoggedIn); - if (loginStateChanged) { - OBSBasic *main = OBSBasic::Get(); - if (main->GetYouTubeAppDock() != nullptr) { - QMetaObject::invokeMethod(main->GetYouTubeAppDock(), "SettingsUpdated", - Qt::QueuedConnection, Q_ARG(bool, !currentlyLoggedIn)); - } - } - }; - if (panel_cookies) { - panel_cookies->CheckForCookie("https://www.youtube.com", "SID", cb); - } -} -#endif diff --git a/frontend/oauth/YoutubeAuth.hpp b/frontend/oauth/YoutubeAuth.hpp index cd560db7d..cecc5f2ac 100644 --- a/frontend/oauth/YoutubeAuth.hpp +++ b/frontend/oauth/YoutubeAuth.hpp @@ -1,38 +1,15 @@ #pragma once -#include -#include -#include -#include - -#include "auth-oauth.hpp" - -#ifdef BROWSER_AVAILABLE -#include "window-dock-browser.hpp" -#include -class YoutubeChatDock : public BrowserDock { - Q_OBJECT - -private: - bool isLoggedIn; - -public: - YoutubeChatDock(const QString &title) : BrowserDock(title) {} - - inline void SetWidget(QCefWidget *widget_) - { - BrowserDock::SetWidget(widget_); - QWidget::connect(cefWidget.get(), &QCefWidget::urlChanged, this, &YoutubeChatDock::YoutubeCookieCheck); - } -private slots: - void YoutubeCookieCheck(); -}; -#endif +#include "OAuth.hpp" inline const std::vector youtubeServices = {{"YouTube - RTMP", Auth::Type::OAuth_LinkedAccount, true, true}, {"YouTube - RTMPS", Auth::Type::OAuth_LinkedAccount, true, true}, {"YouTube - HLS", Auth::Type::OAuth_LinkedAccount, true, true}}; +#ifdef BROWSER_AVAILABLE +class YoutubeChatDock; +#endif + class YoutubeAuth : public OAuthStreamKey { Q_OBJECT