first commit

This commit is contained in:
2026-01-26 22:26:19 +03:00
commit 31fccd85f2
95 changed files with 115400 additions and 0 deletions
+371
View File
@@ -0,0 +1,371 @@
#include "tauth.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QUrl>
#include <QUrlQuery>
#include <QDesktopServices>
#include <QHostAddress>
#include <QByteArray>
#include <QDebug>
#include <QStringList>
#include <QTimer>
TAuth::TAuth(QObject *parent)
: QObject(parent)
, m_server(nullptr)
, m_clientSocket(nullptr)
, m_serverPort(0)
, m_autoOpenBrowser(true)
{
}
TAuth::~TAuth()
{
stopServer();
}
void TAuth::startServer(const QString &authUrl, bool openBrowser)
{
stopServer();
m_authUrl = authUrl;
m_autoOpenBrowser = openBrowser;
m_server = new QTcpServer(this);
// Пытаемся слушать на портах, начиная с 8080
QVector<int> portsToTry = {8089};
for (int port : portsToTry) {
if (m_server->listen(QHostAddress::LocalHost, port)) {
m_serverPort = port;
emit serverStarted(port);
break;
}
}
if (!m_server->isListening()) {
emit errorOccurred("Не удалось запустить сервер на доступных портах");
delete m_server;
m_server = nullptr;
return;
}
connect(m_server, &QTcpServer::newConnection,
this, &TAuth::handleNewConnection);
// Открываем браузер только если указано
if (openBrowser && !authUrl.isEmpty()) {
QDesktopServices::openUrl(QUrl(authUrl));
}
}
void TAuth::stopServer()
{
if (m_server) {
m_server->close();
m_server->deleteLater();
m_server = nullptr;
}
if (m_clientSocket) {
m_clientSocket->disconnect();
m_clientSocket->close();
m_clientSocket->deleteLater();
m_clientSocket = nullptr;
}
m_serverPort = 0;
}
void TAuth::handleNewConnection()
{
if (!m_server) return;
m_clientSocket = m_server->nextPendingConnection();
if (m_clientSocket) {
connect(m_clientSocket, &QTcpSocket::readyRead,
this, &TAuth::readClientData);
connect(m_clientSocket, &QTcpSocket::disconnected,
m_clientSocket, &QTcpSocket::deleteLater);
}
}
void TAuth::readClientData()
{
if (!m_clientSocket || !m_clientSocket->bytesAvailable()) return;
QByteArray requestData = m_clientSocket->readAll();
QString request = QString::fromUtf8(requestData);
QStringList lines = request.split("\r\n");
if (lines.isEmpty()) return;
QString requestLine = lines[0];
QStringList parts = requestLine.split(" ");
if (parts.size() >= 2 && parts[0].toUpper() == "GET") {
QString document = parts[1];
// Проверяем, есть ли в запросе параметры (они могут быть в теле запроса)
// или в реферере
QString referer;
for (const QString &line : lines) {
if (line.startsWith("Referer:", Qt::CaseInsensitive)) {
referer = line.mid(9).trimmed();
break;
}
}
// Обрабатываем обычный redirect
if (document.startsWith("/redirect")) {
handleRedirectRequest(document, m_clientSocket);
}
// Обрабатываем корневой запрос
else if (document == "/" || document == "/?") {
// Проверяем, есть ли хэш в URL
QString fullUrl = document;
if (!referer.isEmpty() && referer.contains("#")) {
// Извлекаем хэш из реферера
QString hash = referer.mid(referer.indexOf("#") + 1);
fullUrl = "/redirect?" + hash;
handleRedirectRequest(fullUrl, m_clientSocket);
} else {
// Или проверяем, есть ли параметры в самом запросе
// (хэш не передается, но могут быть другие параметры)
QString params;
if (document.contains("#")) {
params = document.mid(document.indexOf("#") + 1);
fullUrl = "/redirect?" + params;
handleRedirectRequest(fullUrl, m_clientSocket);
} else {
handleRootRequest(m_clientSocket);
}
}
}
else if (document.startsWith("/da")) {
QString html =
"<!DOCTYPE html>\n<html>\n<head>\n"
" <title>Redirecting...</title>\n</head>\n<body>\n"
" <p>получаю код</p>\n<script>\n"
"var paragraph = window.location.href;\n"
"var urrl = paragraph.replace('localhost:8089/da','localhost:8089/redirect');\n"
"urrl = urrl.replace('#','?');\n"
"console.log(urrl);\n"
"window.location.href = urrl;\n"
"</script>\n</body>\n</html>";
sendResponse(m_clientSocket, html);
}
else {
// Показываем страницу с JavaScript для извлечения хэша
QString html =
"<!DOCTYPE html>\n<html>\n<head>\n"
" <title>Processing...</title>\n</head>\n<body>\n"
" <p>Обработка авторизации...</p>\n<script>\n"
"try {\n"
" // Проверяем, есть ли хэш в URL\n"
" var hash = window.location.hash;\n"
" if (hash) {\n"
" // Преобразуем # в ? для передачи на сервер\n"
" var params = hash.substring(1); // убираем #\n"
" // Перенаправляем на /redirect с параметрами\n"
" window.location.href = '/redirect?' + params;\n"
" } else {\n"
" document.body.innerHTML = '<h2>Нет данных авторизации</h2>';\n"
" }\n"
"} catch(e) {\n"
" document.body.innerHTML = '<h2>Ошибка: ' + e.message + '</h2>';\n"
"}\n"
"</script>\n</body>\n</html>";
sendResponse(m_clientSocket, html);
}
} else {
sendErrorResponse(m_clientSocket, "Invalid request method");
}
}
void TAuth::handleRootRequest(QTcpSocket *socket)
{
QString html =
"<!DOCTYPE html>\n<html>\n<head>\n"
" <title>Processing...</title>\n</head>\n<body>\n"
" <p>Обработка авторизации...</p>\n<script>\n"
"try {\n"
" var hash = window.location.hash;\n"
" if (hash) {\n"
" var params = hash.substring(1);\n"
" window.location.href = '/redirect?' + params;\n"
" } else {\n"
" document.body.innerHTML = '<h2>Нет данных авторизации в URL</h2>';\n"
" }\n"
"} catch(e) {\n"
" document.body.innerHTML = '<h2>Ошибка: ' + e.message + '</h2>';\n"
"}\n"
"</script>\n</body>\n</html>";
sendResponse(socket, html);
}
void TAuth::handleRedirectRequest(const QString &request, QTcpSocket *socket)
{
QString params;
if (request.contains('?')) {
params = request.mid(request.indexOf('?') + 1);
}
QString html;
QString token, code, expiresIn;
// Проверяем наличие access_token
if (params.contains("access_token=")) {
token = extractParam(params, "access_token");
expiresIn = extractExpiresIn(params);
// Формируем полный токен с временем жизни (если есть)
QString fullToken = token;
if (!expiresIn.isEmpty()) {
fullToken += "|" + expiresIn;
}
emit tokenReceived(fullToken);
html =
"<!DOCTYPE html>\n<html>\n<head>\n"
" <title>Success</title>\n</head>\n<body>\n"
"<h2>Authorization Successful!</h2>\n"
"<p>Token received. You can close this window.</p>\n"
"</body>\n</html>";
}
// Проверяем наличие error_description
else if (params.contains("error_description=")) {
QString error = extractErrorDescription(params);
emit errorOccurred(error);
html =
QString("<!DOCTYPE html>\n<html>\n<head>\n"
" <title>Error</title>\n</head>\n<body>\n"
"<h2>Authorization Failed</h2>\n"
"<p>Error: %1</p>\n</body>\n</html>").arg(error);
}
// Проверяем наличие code (для OAuth code flow)
else if (params.contains("code=")) {
code = extractParam(params, "code");
emit codeReceived(code);
html =
"<!DOCTYPE html>\n<html>\n<head>\n"
" <title>Success</title>\n</head>\n<body>\n"
"<h2>Authorization Successful!</h2>\n"
"<p>Code received. You can close this window.</p>\n"
"</body>\n</html>";
}
else {
html =
"<!DOCTYPE html>\n<html>\n<head>\n"
" <title>No Data</title>\n</head>\n<body>\n"
"<h2>No authorization data received</h2>\n"
"<p>Try again or check your authorization URL.</p>\n"
"</body>\n</html>";
sendResponse(socket, html);
return;
}
sendResponse(socket, html);
// Останавливаем сервер после обработки
QTimer::singleShot(1000, this, &TAuth::stopServer);
}
QString TAuth::extractParam(const QString &params, const QString &paramName)
{
QStringList paramList = params.split('&');
for (const QString &param : paramList) {
if (param.startsWith(paramName + "=")) {
QString value = param.mid(paramName.length() + 1);
// Декодируем URL-encoded значения
value = QUrl::fromPercentEncoding(value.toUtf8());
return value;
}
}
return QString();
}
QString TAuth::extractExpiresIn(const QString &params)
{
return extractParam(params, "expires_in");
}
void TAuth::extractAndEmitToken(const QString &params)
{
QString token = extractParam(params, "access_token");
QString expiresIn = extractExpiresIn(params);
if (!token.isEmpty()) {
QString fullToken = token;
if (!expiresIn.isEmpty()) {
fullToken += "|" + expiresIn;
}
emit tokenReceived(fullToken);
}
}
void TAuth::extractAndEmitError(const QString &params)
{
QString error = extractErrorDescription(params);
if (!error.isEmpty()) {
emit errorOccurred(error);
}
}
void TAuth::extractAndEmitCode(const QString &params)
{
QString code = extractParam(params, "code");
if (!code.isEmpty()) {
emit codeReceived(code);
}
}
QString TAuth::extractErrorDescription(const QString &params)
{
QString error = extractParam(params, "error_description");
if (error.isEmpty()) {
error = extractParam(params, "error");
}
if (error.isEmpty()) {
error = "Unknown error";
}
return error;
}
void TAuth::sendResponse(QTcpSocket *socket, const QString &content)
{
if (!socket) return;
QString response =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Content-Length: " + QString::number(content.toUtf8().size()) + "\r\n"
"Connection: close\r\n"
"\r\n" + content;
socket->write(response.toUtf8());
socket->flush();
}
void TAuth::sendErrorResponse(QTcpSocket *socket, const QString &error)
{
if (!socket) return;
QString content = "<html><body><h1>" + error + "</h1></body></html>";
QString response =
"HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Content-Length: " + QString::number(content.toUtf8().size()) + "\r\n"
"Connection: close\r\n"
"\r\n" + content;
socket->write(response.toUtf8());
socket->flush();
}