0654675f32
(Jim note: Adds abstraction to the OAuth class to allow the ability to perform OAuth via external browser, and adds an AuthListener to act as the local auth server.)
87 lines
2.3 KiB
C++
87 lines
2.3 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::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("(&|\\?)code=(?<code>[^&]+)");
|
|
QRegularExpressionMatch match = re.match(redirect);
|
|
if (!match.hasMatch())
|
|
blog(LOG_DEBUG, "no 'code' in server redirect");
|
|
|
|
QString code = match.captured("code");
|
|
|
|
if (code.isEmpty()) {
|
|
auto data = 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();
|
|
}
|
|
}
|