+ проверка срока жизни токена
This commit is contained in:
@@ -87,7 +87,13 @@ void TAuth::handleNewConnection()
|
||||
connect(m_clientSocket, &QTcpSocket::readyRead,
|
||||
this, &TAuth::readClientData);
|
||||
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();
|
||||
QString request = QString::fromUtf8(requestData);
|
||||
|
||||
|
||||
QStringList lines = request.split("\r\n");
|
||||
if (lines.isEmpty()) return;
|
||||
|
||||
@@ -118,7 +123,6 @@ void TAuth::readClientData()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Обрабатываем обычный redirect
|
||||
if (document.startsWith("/redirect")) {
|
||||
handleRedirectRequest(document, m_clientSocket);
|
||||
@@ -237,6 +241,13 @@ void TAuth::handleRedirectRequest(const QString &request, QTcpSocket *socket)
|
||||
"<h2>Authorization Successful!</h2>\n"
|
||||
"<p>Token received. You can close this window.</p>\n"
|
||||
"</body>\n</html>";
|
||||
|
||||
// Отправляем ответ клиенту
|
||||
sendResponse(socket, html);
|
||||
|
||||
// Останавливаем сервер СРАЗУ
|
||||
QTimer::singleShot(100, this, &TAuth::stopServer);
|
||||
return;
|
||||
}
|
||||
// Проверяем наличие 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"
|
||||
"<p>Code received. You can close this window.</p>\n"
|
||||
"</body>\n</html>";
|
||||
|
||||
// Отправляем ответ клиенту
|
||||
sendResponse(socket, html);
|
||||
|
||||
// Останавливаем сервер СРАЗУ
|
||||
QTimer::singleShot(100, this, &TAuth::stopServer);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
html =
|
||||
@@ -269,13 +287,16 @@ void TAuth::handleRedirectRequest(const QString &request, QTcpSocket *socket)
|
||||
"<p>Try again or check your authorization URL.</p>\n"
|
||||
"</body>\n</html>";
|
||||
sendResponse(socket, html);
|
||||
|
||||
// Останавливаем сервер через 5 секунд если нет данных
|
||||
QTimer::singleShot(5000, this, &TAuth::stopServer);
|
||||
return;
|
||||
}
|
||||
|
||||
sendResponse(socket, html);
|
||||
|
||||
// Останавливаем сервер после обработки
|
||||
QTimer::singleShot(1000, this, &TAuth::stopServer);
|
||||
// Останавливаем сервер через 5 секунд для других случаев
|
||||
QTimer::singleShot(5000, this, &TAuth::stopServer);
|
||||
}
|
||||
|
||||
QString TAuth::extractParam(const QString ¶ms, const QString ¶mName)
|
||||
|
||||
+101
@@ -591,3 +591,104 @@ void TTwAPI::parseBadgesFromApi(const QString &jsonString, QVector<ChatBadge> &b
|
||||
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
@@ -54,7 +54,7 @@ bool WebSocketClient::connectToServer(const QString &url)
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebSocketClient::connectToTwitchChat(const QString &oauthToken,
|
||||
bool WebSocketClient::connectToTwitchChat(const QString &oauthToken,
|
||||
const QString &nickname,
|
||||
const QString &channel)
|
||||
{
|
||||
@@ -65,7 +65,7 @@ void WebSocketClient::connectToTwitchChat(const QString &oauthToken,
|
||||
// URL для подключения к Twitch IRC через WebSocket
|
||||
QString url = "wss://irc-ws.chat.twitch.tv:443";
|
||||
|
||||
connectToServer(url);
|
||||
return connectToServer(url);
|
||||
}
|
||||
|
||||
void WebSocketClient::onConnectedInternal()
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ public:
|
||||
Q_INVOKABLE bool isConnected() const;
|
||||
|
||||
// Методы для 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 sendChatMessage(const QString &channel, const QString &message);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user