115 lines
2.8 KiB
C++
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();
|
|
}
|
|
}
|