+ проверка срока жизни токена

This commit is contained in:
2026-02-11 06:58:55 +03:00
parent 39f0c447c1
commit 47c0c7ed85
4 changed files with 130 additions and 8 deletions
+26 -5
View File
@@ -87,7 +87,13 @@ void TAuth::handleNewConnection()
connect(m_clientSocket, &QTcpSocket::readyRead, connect(m_clientSocket, &QTcpSocket::readyRead,
this, &TAuth::readClientData); this, &TAuth::readClientData);
connect(m_clientSocket, &QTcpSocket::disconnected, connect(m_clientSocket, &QTcpSocket::disconnected,
m_clientSocket, &QTcpSocket::deleteLater); this, [this]() {
// Удаляем сокет после отключения
if (m_clientSocket) {
m_clientSocket->deleteLater();
m_clientSocket = nullptr;
}
});
} }
} }
@@ -98,7 +104,6 @@ void TAuth::readClientData()
QByteArray requestData = m_clientSocket->readAll(); QByteArray requestData = m_clientSocket->readAll();
QString request = QString::fromUtf8(requestData); QString request = QString::fromUtf8(requestData);
QStringList lines = request.split("\r\n"); QStringList lines = request.split("\r\n");
if (lines.isEmpty()) return; if (lines.isEmpty()) return;
@@ -118,7 +123,6 @@ void TAuth::readClientData()
} }
} }
// Обрабатываем обычный redirect // Обрабатываем обычный redirect
if (document.startsWith("/redirect")) { if (document.startsWith("/redirect")) {
handleRedirectRequest(document, m_clientSocket); handleRedirectRequest(document, m_clientSocket);
@@ -237,6 +241,13 @@ void TAuth::handleRedirectRequest(const QString &request, QTcpSocket *socket)
"<h2>Authorization Successful!</h2>\n" "<h2>Authorization Successful!</h2>\n"
"<p>Token received. You can close this window.</p>\n" "<p>Token received. You can close this window.</p>\n"
"</body>\n</html>"; "</body>\n</html>";
// Отправляем ответ клиенту
sendResponse(socket, html);
// Останавливаем сервер СРАЗУ
QTimer::singleShot(100, this, &TAuth::stopServer);
return;
} }
// Проверяем наличие error_description // Проверяем наличие error_description
else if (params.contains("error_description=")) { else if (params.contains("error_description=")) {
@@ -260,6 +271,13 @@ void TAuth::handleRedirectRequest(const QString &request, QTcpSocket *socket)
"<h2>Authorization Successful!</h2>\n" "<h2>Authorization Successful!</h2>\n"
"<p>Code received. You can close this window.</p>\n" "<p>Code received. You can close this window.</p>\n"
"</body>\n</html>"; "</body>\n</html>";
// Отправляем ответ клиенту
sendResponse(socket, html);
// Останавливаем сервер СРАЗУ
QTimer::singleShot(100, this, &TAuth::stopServer);
return;
} }
else { else {
html = html =
@@ -269,13 +287,16 @@ void TAuth::handleRedirectRequest(const QString &request, QTcpSocket *socket)
"<p>Try again or check your authorization URL.</p>\n" "<p>Try again or check your authorization URL.</p>\n"
"</body>\n</html>"; "</body>\n</html>";
sendResponse(socket, html); sendResponse(socket, html);
// Останавливаем сервер через 5 секунд если нет данных
QTimer::singleShot(5000, this, &TAuth::stopServer);
return; return;
} }
sendResponse(socket, html); sendResponse(socket, html);
// Останавливаем сервер после обработки // Останавливаем сервер через 5 секунд для других случаев
QTimer::singleShot(1000, this, &TAuth::stopServer); QTimer::singleShot(5000, this, &TAuth::stopServer);
} }
QString TAuth::extractParam(const QString &params, const QString &paramName) QString TAuth::extractParam(const QString &params, const QString &paramName)
+101
View File
@@ -591,3 +591,104 @@ void TTwAPI::parseBadgesFromApi(const QString &jsonString, QVector<ChatBadge> &b
badges.append(badge); badges.append(badge);
} }
} }
bool TTwAPI::validateTwitchToken(const QString &tokenName,
const QString &tokenValue,
int &daysValid)
{
daysValid = 0;
if (tokenValue.trimmed().isEmpty()) {
toLog(1, "TTwAPI::validateTwitchToken", "Пустой токен: " + tokenName);
return false;
}
QUrl url("https://id.twitch.tv/oauth2/validate");
QNetworkRequest request(url);
// Устанавливаем заголовки
request.setHeader(QNetworkRequest::UserAgentHeader, "YourApp/1.0");
request.setRawHeader("Accept", "application/json");
// Формируем заголовок Authorization
QString authHeader = "OAuth " + tokenValue;
request.setRawHeader("Authorization", authHeader.toUtf8());
// Отправляем GET запрос
QNetworkReply *reply = m_networkManager->get(request);
if (!reply) {
toLog(2, "TTwAPI::validateTwitchToken", "Не удалось создать запрос для токена: " + tokenName);
return false;
}
// Ожидание завершения запроса
QEventLoop loop;
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
// Проверяем статус ответа
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QByteArray responseData = reply->readAll();
QString responseText = QString::fromUtf8(responseData);
// Обрабатываем ошибки сети
if (reply->error() != QNetworkReply::NoError) {
QString errorMsg = QString("Ошибка сети: %1 - %2")
.arg(reply->error())
.arg(reply->errorString());
toLog(2, "TTwAPI::validateTwitchToken", errorMsg);
reply->deleteLater();
return false;
}
reply->deleteLater();
// Обработка HTTP статусов
if (statusCode == 200) {
// Успешная валидация
QJsonDocument doc = QJsonDocument::fromJson(responseData);
if (!doc.isObject()) {
toLog(2, "TTwAPI::validateTwitchToken", "Ошибка парсинга JSON для токена: " + tokenName);
return false;
}
QJsonObject jsonObj = doc.object();
// Извлекаем expires_in (в секундах)
if (jsonObj.contains("expires_in") && jsonObj["expires_in"].isDouble()) {
int expiresInSeconds = jsonObj["expires_in"].toInt();
daysValid = qRound(expiresInSeconds / 86400.0); // Конвертируем секунды в дни
// Логируем информацию о токене
QString logMsg = QString("Токен '%1' действителен. Осталось: %2 дней. "
"Client ID: %3, Логин: %4")
.arg(tokenName)
.arg(daysValid)
.arg(jsonObj.value("client_id").toString("N/A"))
.arg(jsonObj.value("login").toString("N/A"));
toLog(0, "TTwAPI::validateTwitchToken", logMsg);
return true;
} else {
toLog(2, "TTwAPI::validateTwitchToken",
QString("В ответе отсутствует expires_in для токена: %1").arg(tokenName));
return false;
}
}
else if (statusCode == 401) {
// Невалидный токен
toLog(2, "TTwAPI::validateTwitchToken",
QString("Токен '%1' невалиден (HTTP 401)").arg(tokenName));
return false;
}
else {
// Другие HTTP ошибки
QString errorMsg = QString("HTTP %1 для токена '%2': %3")
.arg(statusCode)
.arg(tokenName)
.arg(responseText);
toLog(2, "TTwAPI::validateTwitchToken", errorMsg);
return false;
}
}
+2 -2
View File
@@ -54,7 +54,7 @@ bool WebSocketClient::connectToServer(const QString &url)
return true; return true;
} }
void WebSocketClient::connectToTwitchChat(const QString &oauthToken, bool WebSocketClient::connectToTwitchChat(const QString &oauthToken,
const QString &nickname, const QString &nickname,
const QString &channel) const QString &channel)
{ {
@@ -65,7 +65,7 @@ void WebSocketClient::connectToTwitchChat(const QString &oauthToken,
// URL для подключения к Twitch IRC через WebSocket // URL для подключения к Twitch IRC через WebSocket
QString url = "wss://irc-ws.chat.twitch.tv:443"; QString url = "wss://irc-ws.chat.twitch.tv:443";
connectToServer(url); return connectToServer(url);
} }
void WebSocketClient::onConnectedInternal() void WebSocketClient::onConnectedInternal()
+1 -1
View File
@@ -23,7 +23,7 @@ public:
Q_INVOKABLE bool isConnected() const; Q_INVOKABLE bool isConnected() const;
// Методы для Twitch чата // Методы для Twitch чата
Q_INVOKABLE void connectToTwitchChat(const QString &oauthToken, const QString &nickname, const QString &channel); Q_INVOKABLE bool connectToTwitchChat(const QString &oauthToken, const QString &nickname, const QString &channel);
Q_INVOKABLE void joinChannel(const QString &channel); Q_INVOKABLE void joinChannel(const QString &channel);
Q_INVOKABLE void sendChatMessage(const QString &channel, const QString &message); Q_INVOKABLE void sendChatMessage(const QString &channel, const QString &message);