0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 13:08:50 +02:00
obs-studio/UI/auth-mixer.cpp
jp9000 01c78bffc5 UI: Do not display threaded message boxes on startup
The message boxes that tell you that the browser is initializing or that
you're authenticating with twitch are annoying on startup.  It makes
sense to do it in the settings/autoconfig dialogs where you sort of need
to know what's going on while waiting for it to connect, but on startup
it's not really necessary and can be kind of annoying.
2019-02-20 17:35:02 -08:00

314 lines
6.9 KiB
C++

#include "auth-mixer.hpp"
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <qt-wrappers.hpp>
#include <obs-app.hpp>
#include "window-basic-main.hpp"
#include "remote-text.hpp"
#include <json11.hpp>
#include <ctime>
#include "ui-config.h"
#include "obf.h"
using namespace json11;
#include <browser-panel.hpp>
extern QCef *cef;
extern QCefCookieManager *panel_cookies;
/* ------------------------------------------------------------------------- */
#define MIXER_AUTH_URL \
"https://obsproject.com/app-auth/mixer?action=redirect"
#define MIXER_TOKEN_URL \
"https://obsproject.com/app-auth/mixer-token"
#define MIXER_SCOPE_VERSION 1
static Auth::Def mixerDef = {
"Mixer",
Auth::Type::OAuth_StreamKey
};
/* ------------------------------------------------------------------------- */
MixerAuth::MixerAuth(const Def &d)
: OAuthStreamKey(d)
{
}
bool MixerAuth::GetChannelInfo()
try {
std::string client_id = MIXER_CLIENTID;
deobfuscate_str(&client_id[0], MIXER_HASH);
if (!GetToken(MIXER_TOKEN_URL, client_id, MIXER_SCOPE_VERSION))
return false;
if (token.empty())
return false;
if (!key_.empty())
return true;
std::string auth;
auth += "Authorization: Bearer ";
auth += token;
std::vector<std::string> headers;
headers.push_back(std::string("Client-ID: ") + client_id);
headers.push_back(std::move(auth));
std::string output;
std::string error;
Json json;
bool success;
if (id.empty()) {
auto func = [&] () {
success = GetRemoteFile(
"https://mixer.com/api/v1/users/current",
output,
error,
nullptr,
"application/json",
nullptr,
headers,
nullptr,
5);
};
ExecThreadedWithoutBlocking(
func,
QTStr("Auth.LoadingChannel.Title"),
QTStr("Auth.LoadingChannel.Text").arg(service()));
if (!success || output.empty())
throw ErrorInfo("Failed to get user info from remote",
error);
Json json = Json::parse(output, error);
if (!error.empty())
throw ErrorInfo("Failed to parse json", error);
error = json["error"].string_value();
if (!error.empty())
throw ErrorInfo(error,
json["error_description"].string_value());
id = std::to_string(json["channel"]["id"].int_value());
name = json["channel"]["token"].string_value();
}
/* ------------------ */
std::string url;
url += "https://mixer.com/api/v1/channels/";
url += id;
url += "/details";
output.clear();
auto func = [&] () {
success = GetRemoteFile(
url.c_str(),
output,
error,
nullptr,
"application/json",
nullptr,
headers,
nullptr,
5);
};
ExecThreadedWithoutBlocking(
func,
QTStr("Auth.LoadingChannel.Title"),
QTStr("Auth.LoadingChannel.Text").arg(service()));
if (!success || output.empty())
throw ErrorInfo("Failed to get stream key from remote", error);
json = Json::parse(output, error);
if (!error.empty())
throw ErrorInfo("Failed to parse json", error);
error = json["error"].string_value();
if (!error.empty())
throw ErrorInfo(error, json["error_description"].string_value());
key_ = id + "-" + json["streamKey"].string_value();
return true;
} catch (ErrorInfo info) {
QString title = QTStr("Auth.ChannelFailure.Title");
QString text = QTStr("Auth.ChannelFailure.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 MixerAuth::SaveInternal()
{
OBSBasic *main = OBSBasic::Get();
config_set_string(main->Config(), service(), "Name", name.c_str());
config_set_string(main->Config(), service(), "Id", id.c_str());
if (uiLoaded) {
config_set_string(main->Config(), service(), "DockState",
main->saveState().toBase64().constData());
}
OAuthStreamKey::SaveInternal();
}
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 MixerAuth::LoadInternal()
{
if (!cef)
return false;
OBSBasic *main = OBSBasic::Get();
name = get_config_str(main, service(), "Name");
id = get_config_str(main, service(), "Id");
firstLoad = false;
return OAuthStreamKey::LoadInternal();
}
class MixerChat : public QDockWidget {
public:
inline MixerChat() : QDockWidget() {}
QScopedPointer<QCefWidget> widget;
};
void MixerAuth::LoadUI()
{
if (uiLoaded)
return;
if (!GetChannelInfo())
return;
OBSBasic::InitBrowserPanelSafeBlock();
OBSBasic *main = OBSBasic::Get();
std::string url;
url += "https://mixer.com/embed/chat/";
url += id;
QSize size = main->frameSize();
QPoint pos = main->pos();
chat.reset(new MixerChat());
chat->setObjectName("mixerChat");
chat->resize(300, 600);
chat->setMinimumSize(200, 300);
chat->setWindowTitle(QTStr("Auth.Chat"));
chat->setAllowedAreas(Qt::AllDockWidgetAreas);
QCefWidget *browser = cef->create_widget(nullptr, url, panel_cookies);
chat->setWidget(browser);
main->addDockWidget(Qt::RightDockWidgetArea, chat.data());
chatMenu.reset(main->AddDockWidget(chat.data()));
/* ----------------------------------- */
chat->setFloating(true);
chat->move(pos.x() + size.width() - chat->width() - 50, pos.y() + 50);
if (firstLoad) {
chat->setVisible(true);
} else {
const char *dockStateStr = config_get_string(main->Config(),
service(), "DockState");
QByteArray dockState =
QByteArray::fromBase64(QByteArray(dockStateStr));
main->restoreState(dockState);
}
uiLoaded = true;
}
bool MixerAuth::RetryLogin()
{
OAuthLogin login(OBSBasic::Get(), MIXER_AUTH_URL, false);
cef->add_popup_whitelist_url("about:blank", &login);
if (login.exec() == QDialog::Rejected) {
return false;
}
std::shared_ptr<MixerAuth> auth = std::make_shared<MixerAuth>(mixerDef);
std::string client_id = MIXER_CLIENTID;
deobfuscate_str(&client_id[0], MIXER_HASH);
return GetToken(MIXER_TOKEN_URL, client_id, MIXER_SCOPE_VERSION,
QT_TO_UTF8(login.GetCode()), true);
}
std::shared_ptr<Auth> MixerAuth::Login(QWidget *parent)
{
OAuthLogin login(parent, MIXER_AUTH_URL, false);
cef->add_popup_whitelist_url("about:blank", &login);
if (login.exec() == QDialog::Rejected) {
return nullptr;
}
std::shared_ptr<MixerAuth> auth = std::make_shared<MixerAuth>(mixerDef);
std::string client_id = MIXER_CLIENTID;
deobfuscate_str(&client_id[0], MIXER_HASH);
if (!auth->GetToken(MIXER_TOKEN_URL, client_id, MIXER_SCOPE_VERSION,
QT_TO_UTF8(login.GetCode()))) {
return nullptr;
}
std::string error;
if (auth->GetChannelInfo()) {
return auth;
}
return nullptr;
}
static std::shared_ptr<Auth> CreateMixerAuth()
{
return std::make_shared<MixerAuth>(mixerDef);
}
static void DeleteCookies()
{
if (panel_cookies) {
panel_cookies->DeleteCookies("mixer.com", std::string());
panel_cookies->DeleteCookies("microsoft.com", std::string());
}
}
void RegisterMixerAuth()
{
OAuth::RegisterOAuth(
mixerDef,
CreateMixerAuth,
MixerAuth::Login,
DeleteCookies);
}