AuthListener.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #include "AuthListener.hpp"
  2. #include <OBSApp.hpp>
  3. #include <qt-wrappers.hpp>
  4. #include <QRegularExpression>
  5. #include <QTcpServer>
  6. #include <QTcpSocket>
  7. #include "moc_AuthListener.cpp"
  8. #define LOGO_URL "https://obsproject.com/assets/images/new_icon_small-r.png"
  9. static const QString serverResponseHeader = QStringLiteral("HTTP/1.0 200 OK\n"
  10. "Connection: close\n"
  11. "Content-Type: text/html; charset=UTF-8\n"
  12. "Server: OBS Studio\n"
  13. "\n"
  14. "<html><head><title>OBS Studio"
  15. "</title></head>");
  16. static const QString responseTemplate = "<center>"
  17. "<img src=\"" LOGO_URL
  18. "\" alt=\"OBS\" class=\"center\" height=\"60\" width=\"60\">"
  19. "</center>"
  20. "<center><p style=\"font-family:verdana; font-size:13pt\">%1</p></center>";
  21. AuthListener::AuthListener(QObject *parent) : QObject(parent)
  22. {
  23. server = new QTcpServer(this);
  24. connect(server, &QTcpServer::newConnection, this, &AuthListener::NewConnection);
  25. if (!server->listen(QHostAddress::LocalHost, 0)) {
  26. blog(LOG_DEBUG, "Server could not start");
  27. emit fail();
  28. } else {
  29. blog(LOG_DEBUG, "Server started at port %d", server->serverPort());
  30. }
  31. }
  32. quint16 AuthListener::GetPort()
  33. {
  34. return server ? server->serverPort() : 0;
  35. }
  36. void AuthListener::SetState(QString state)
  37. {
  38. this->state = state;
  39. }
  40. void AuthListener::NewConnection()
  41. {
  42. QTcpSocket *socket = server->nextPendingConnection();
  43. if (socket) {
  44. connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater);
  45. connect(socket, &QTcpSocket::readyRead, socket, [&, socket]() {
  46. QByteArray buffer;
  47. while (socket->bytesAvailable() > 0) {
  48. buffer.append(socket->readAll());
  49. }
  50. socket->write(QT_TO_UTF8(serverResponseHeader));
  51. QString redirect = QString::fromLatin1(buffer);
  52. blog(LOG_DEBUG, "redirect: %s", QT_TO_UTF8(redirect));
  53. QRegularExpression re_state("(&|\\?)state=(?<state>[^&]+)");
  54. QRegularExpression re_code("(&|\\?)code=(?<code>[^&]+)");
  55. QRegularExpressionMatch match = re_state.match(redirect);
  56. QString code;
  57. if (match.hasMatch()) {
  58. if (state == match.captured("state")) {
  59. match = re_code.match(redirect);
  60. if (!match.hasMatch())
  61. blog(LOG_DEBUG, "no 'code' "
  62. "in server "
  63. "redirect");
  64. code = match.captured("code");
  65. } else {
  66. blog(LOG_WARNING, "state mismatch "
  67. "while handling "
  68. "redirect");
  69. }
  70. } else {
  71. blog(LOG_DEBUG, "no 'state' in "
  72. "server redirect");
  73. }
  74. if (code.isEmpty()) {
  75. auto data = responseTemplate.arg(QTStr("YouTube.Auth.NoCode"));
  76. socket->write(QT_TO_UTF8(data));
  77. emit fail();
  78. } else {
  79. auto data = responseTemplate.arg(QTStr("YouTube.Auth.Ok"));
  80. socket->write(QT_TO_UTF8(data));
  81. emit ok(code);
  82. }
  83. socket->flush();
  84. socket->close();
  85. });
  86. } else {
  87. emit fail();
  88. }
  89. }