auth-listener.cpp 2.8 KB

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