File: auth-listener.cpp

package info (click to toggle)
obs-studio 30.2.3%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 47,852 kB
  • sloc: ansic: 202,137; cpp: 112,402; makefile: 868; python: 599; sh: 275; javascript: 19
file content (114 lines) | stat: -rw-r--r-- 2,880 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#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();
	}
}