obs-studio/UI/auth-listener.cpp

115 lines
2.8 KiB
C++

#include <auth-listener.hpp>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QString>
#include <QtNetwork/QTcpSocket>
#include "obs-app.hpp"
#include "qt-wrappers.hpp"
#define LOGO_URL "https://obsproject.com/assets/images/new_icon_small-r.png"
static const QString serverResponseHeader =
QStringLiteral("HTTP/1.0 200 OK\n"
"Connection: close\n"
"Content-Type: text/html; charset=UTF-8\n"
"Server: OBS Studio\n"
"\n"
"<html><head><title>OBS Studio"
"</title></head>");
static const QString responseTemplate =
"<center>"
"<img src=\"" LOGO_URL
"\" alt=\"OBS\" class=\"center\" height=\"60\" width=\"60\">"
"</center>"
"<center><p style=\"font-family:verdana; font-size:13pt\">%1</p></center>";
AuthListener::AuthListener(QObject *parent) : QObject(parent)
{
server = new QTcpServer(this);
connect(server, &QTcpServer::newConnection, this,
&AuthListener::NewConnection);
if (!server->listen(QHostAddress::LocalHost, 0)) {
blog(LOG_DEBUG, "Server could not start");
emit fail();
} else {
blog(LOG_DEBUG, "Server started at port %d",
server->serverPort());
}
}
quint16 AuthListener::GetPort()
{
return server ? server->serverPort() : 0;
}
void AuthListener::SetState(QString state)
{
this->state = state;
}
void AuthListener::NewConnection()
{
QTcpSocket *socket = server->nextPendingConnection();
if (socket) {
connect(socket, &QTcpSocket::disconnected, socket,
&QTcpSocket::deleteLater);
connect(socket, &QTcpSocket::readyRead, socket, [&, socket]() {
QByteArray buffer;
while (socket->bytesAvailable() > 0) {
buffer.append(socket->readAll());
}
socket->write(QT_TO_UTF8(serverResponseHeader));
QString redirect = QString::fromLatin1(buffer);
blog(LOG_DEBUG, "redirect: %s", QT_TO_UTF8(redirect));
QRegularExpression re_state(
"(&|\\?)state=(?<state>[^&]+)");
QRegularExpression re_code(
"(&|\\?)code=(?<code>[^&]+)");
QRegularExpressionMatch match =
re_state.match(redirect);
QString code;
if (match.hasMatch()) {
if (state == match.captured("state")) {
match = re_code.match(redirect);
if (!match.hasMatch())
blog(LOG_DEBUG, "no 'code' "
"in server "
"redirect");
code = match.captured("code");
} else {
blog(LOG_WARNING, "state mismatch "
"while handling "
"redirect");
}
} else {
blog(LOG_DEBUG, "no 'state' in "
"server redirect");
}
if (code.isEmpty()) {
auto data = responseTemplate.arg(
QTStr("YouTube.Auth.NoCode"));
socket->write(QT_TO_UTF8(data));
emit fail();
} else {
auto data = responseTemplate.arg(
QTStr("YouTube.Auth.Ok"));
socket->write(QT_TO_UTF8(data));
emit ok(code);
}
socket->flush();
socket->close();
});
} else {
emit fail();
}
}