+ проверка срока жизни токена
This commit is contained in:
@@ -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 ¶ms, const QString ¶mName)
|
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);
|
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;
|
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
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user