auth-restream.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #include "auth-restream.hpp"
  2. #include <QPushButton>
  3. #include <QHBoxLayout>
  4. #include <QVBoxLayout>
  5. #include <qt-wrappers.hpp>
  6. #include <json11.hpp>
  7. #include <ctime>
  8. #include <sstream>
  9. #include <obs-app.hpp>
  10. #include "window-basic-main.hpp"
  11. #include "remote-text.hpp"
  12. #include "ui-config.h"
  13. #include "obf.h"
  14. #include <browser-panel.hpp>
  15. using namespace json11;
  16. extern QCef *cef;
  17. extern QCefCookieManager *panel_cookies;
  18. /* ------------------------------------------------------------------------- */
  19. #define RESTREAM_AUTH_URL \
  20. "https://obsproject.com/app-auth/restream?action=redirect"
  21. #define RESTREAM_TOKEN_URL "https://obsproject.com/app-auth/restream-token"
  22. #define RESTREAM_STREAMKEY_URL "https://api.restream.io/v2/user/streamKey"
  23. #define RESTREAM_SCOPE_VERSION 1
  24. static Auth::Def restreamDef = {"Restream", Auth::Type::OAuth_StreamKey};
  25. /* ------------------------------------------------------------------------- */
  26. RestreamAuth::RestreamAuth(const Def &d) : OAuthStreamKey(d) {}
  27. bool RestreamAuth::GetChannelInfo()
  28. try {
  29. std::string client_id = RESTREAM_CLIENTID;
  30. deobfuscate_str(&client_id[0], RESTREAM_HASH);
  31. if (!GetToken(RESTREAM_TOKEN_URL, client_id, RESTREAM_SCOPE_VERSION))
  32. return false;
  33. if (token.empty())
  34. return false;
  35. if (!key_.empty())
  36. return true;
  37. std::string auth;
  38. auth += "Authorization: Bearer ";
  39. auth += token;
  40. std::vector<std::string> headers;
  41. headers.push_back(std::string("Client-ID: ") + client_id);
  42. headers.push_back(std::move(auth));
  43. std::string output;
  44. std::string error;
  45. Json json;
  46. bool success;
  47. auto func = [&]() {
  48. success = GetRemoteFile(RESTREAM_STREAMKEY_URL, output, error,
  49. nullptr, "application/json", nullptr,
  50. headers, nullptr, 5);
  51. };
  52. ExecThreadedWithoutBlocking(
  53. func, QTStr("Auth.LoadingChannel.Title"),
  54. QTStr("Auth.LoadingChannel.Text").arg(service()));
  55. if (!success || output.empty())
  56. throw ErrorInfo("Failed to get stream key from remote", error);
  57. json = Json::parse(output, error);
  58. if (!error.empty())
  59. throw ErrorInfo("Failed to parse json", error);
  60. error = json["error"].string_value();
  61. if (!error.empty())
  62. throw ErrorInfo(error,
  63. json["error_description"].string_value());
  64. key_ = json["streamKey"].string_value();
  65. return true;
  66. } catch (ErrorInfo info) {
  67. QString title = QTStr("Auth.ChannelFailure.Title");
  68. QString text = QTStr("Auth.ChannelFailure.Text")
  69. .arg(service(), info.message.c_str(),
  70. info.error.c_str());
  71. QMessageBox::warning(OBSBasic::Get(), title, text);
  72. blog(LOG_WARNING, "%s: %s: %s", __FUNCTION__, info.message.c_str(),
  73. info.error.c_str());
  74. return false;
  75. }
  76. void RestreamAuth::SaveInternal()
  77. {
  78. OBSBasic *main = OBSBasic::Get();
  79. config_set_string(main->Config(), service(), "DockState",
  80. main->saveState().toBase64().constData());
  81. OAuthStreamKey::SaveInternal();
  82. }
  83. static inline std::string get_config_str(OBSBasic *main, const char *section,
  84. const char *name)
  85. {
  86. const char *val = config_get_string(main->Config(), section, name);
  87. return val ? val : "";
  88. }
  89. bool RestreamAuth::LoadInternal()
  90. {
  91. firstLoad = false;
  92. return OAuthStreamKey::LoadInternal();
  93. }
  94. class RestreamWidget : public QDockWidget {
  95. public:
  96. inline RestreamWidget() : QDockWidget() {}
  97. QScopedPointer<QCefWidget> widget;
  98. };
  99. void RestreamAuth::LoadUI()
  100. {
  101. if (uiLoaded)
  102. return;
  103. if (!GetChannelInfo())
  104. return;
  105. OBSBasic::InitBrowserPanelSafeBlock();
  106. OBSBasic *main = OBSBasic::Get();
  107. QCefWidget *browser;
  108. std::string url;
  109. std::string script;
  110. /* ----------------------------------- */
  111. url = "https://restream.io/chat-application";
  112. QSize size = main->frameSize();
  113. QPoint pos = main->pos();
  114. chat.reset(new RestreamWidget());
  115. chat->setObjectName("restreamChat");
  116. chat->resize(420, 600);
  117. chat->setMinimumSize(200, 300);
  118. chat->setWindowTitle(QTStr("Auth.Chat"));
  119. chat->setAllowedAreas(Qt::AllDockWidgetAreas);
  120. browser = cef->create_widget(nullptr, url, panel_cookies);
  121. chat->setWidget(browser);
  122. main->addDockWidget(Qt::RightDockWidgetArea, chat.data());
  123. chatMenu.reset(main->AddDockWidget(chat.data()));
  124. /* ----------------------------------- */
  125. url = "https://restream.io/titles/embed";
  126. info.reset(new RestreamWidget());
  127. info->setObjectName("restreamInfo");
  128. info->resize(410, 600);
  129. info->setMinimumSize(200, 150);
  130. info->setWindowTitle(QTStr("Auth.StreamInfo"));
  131. info->setAllowedAreas(Qt::AllDockWidgetAreas);
  132. browser = cef->create_widget(nullptr, url, panel_cookies);
  133. info->setWidget(browser);
  134. main->addDockWidget(Qt::RightDockWidgetArea, info.data());
  135. infoMenu.reset(main->AddDockWidget(info.data()));
  136. /* ----------------------------------- */
  137. chat->setFloating(true);
  138. info->setFloating(true);
  139. chat->move(pos.x() + size.width() - chat->width() - 50, pos.y() + 50);
  140. info->move(pos.x() + 40, pos.y() + 50);
  141. if (firstLoad) {
  142. chat->setVisible(true);
  143. info->setVisible(true);
  144. } else {
  145. const char *dockStateStr = config_get_string(
  146. main->Config(), service(), "DockState");
  147. QByteArray dockState =
  148. QByteArray::fromBase64(QByteArray(dockStateStr));
  149. main->restoreState(dockState);
  150. }
  151. uiLoaded = true;
  152. }
  153. bool RestreamAuth::RetryLogin()
  154. {
  155. OAuthLogin login(OBSBasic::Get(), RESTREAM_AUTH_URL, false);
  156. cef->add_popup_whitelist_url("about:blank", &login);
  157. if (login.exec() == QDialog::Rejected) {
  158. return false;
  159. }
  160. std::shared_ptr<RestreamAuth> auth =
  161. std::make_shared<RestreamAuth>(restreamDef);
  162. std::string client_id = RESTREAM_CLIENTID;
  163. deobfuscate_str(&client_id[0], RESTREAM_HASH);
  164. return GetToken(RESTREAM_TOKEN_URL, client_id, RESTREAM_SCOPE_VERSION,
  165. QT_TO_UTF8(login.GetCode()), true);
  166. }
  167. std::shared_ptr<Auth> RestreamAuth::Login(QWidget *parent)
  168. {
  169. OAuthLogin login(parent, RESTREAM_AUTH_URL, false);
  170. cef->add_popup_whitelist_url("about:blank", &login);
  171. if (login.exec() == QDialog::Rejected) {
  172. return nullptr;
  173. }
  174. std::shared_ptr<RestreamAuth> auth =
  175. std::make_shared<RestreamAuth>(restreamDef);
  176. std::string client_id = RESTREAM_CLIENTID;
  177. deobfuscate_str(&client_id[0], RESTREAM_HASH);
  178. if (!auth->GetToken(RESTREAM_TOKEN_URL, client_id,
  179. RESTREAM_SCOPE_VERSION,
  180. QT_TO_UTF8(login.GetCode()))) {
  181. return nullptr;
  182. }
  183. std::string error;
  184. if (auth->GetChannelInfo()) {
  185. return auth;
  186. }
  187. return nullptr;
  188. }
  189. static std::shared_ptr<Auth> CreateRestreamAuth()
  190. {
  191. return std::make_shared<RestreamAuth>(restreamDef);
  192. }
  193. static void DeleteCookies()
  194. {
  195. if (panel_cookies) {
  196. panel_cookies->DeleteCookies("restream.io", std::string());
  197. }
  198. }
  199. void RegisterRestreamAuth()
  200. {
  201. OAuth::RegisterOAuth(restreamDef, CreateRestreamAuth,
  202. RestreamAuth::Login, DeleteCookies);
  203. }