fix(update,security): add release notes in updater and bump to 2.2.1
All checks were successful
Desktop CI / tests (push) Successful in 13s
Desktop Release / release (push) Successful in 3m30s

This commit is contained in:
2026-02-15 23:51:44 +03:00
parent e0628b1792
commit 4b3347a069
4 changed files with 42 additions and 12 deletions

View File

@@ -1 +1 @@
APP_VERSION = "2.2.0" APP_VERSION = "2.2.1"

46
main.py
View File

@@ -2,7 +2,6 @@
import os import os
import shutil import shutil
import sys import sys
import threading
import time import time
from PySide6.QtCore import QProcess from PySide6.QtCore import QProcess
@@ -463,7 +462,7 @@ class VkChatManager(QMainWindow):
self._log_event("update_channel", f"update_channel={self.update_channel}") self._log_event("update_channel", f"update_channel={self.update_channel}")
def check_for_updates(self, silent_no_updates=False): def check_for_updates(self, silent_no_updates=False):
if self.update_thread and self.update_thread.is_alive(): if self.update_thread and self.update_thread.isRunning():
return return
self._update_check_silent = silent_no_updates self._update_check_silent = silent_no_updates
@@ -477,9 +476,16 @@ class VkChatManager(QMainWindow):
request_timeout=UPDATE_REQUEST_TIMEOUT, request_timeout=UPDATE_REQUEST_TIMEOUT,
channel=self.update_channel, channel=self.update_channel,
) )
self.update_thread = QThread(self)
self.update_checker.moveToThread(self.update_thread)
self.update_thread.started.connect(self.update_checker.run)
self.update_checker.check_finished.connect(self._on_update_check_finished) self.update_checker.check_finished.connect(self._on_update_check_finished)
self.update_checker.check_failed.connect(self._on_update_check_failed) self.update_checker.check_failed.connect(self._on_update_check_failed)
self.update_thread = threading.Thread(target=self.update_checker.run, daemon=True) self.update_checker.check_finished.connect(self.update_thread.quit)
self.update_checker.check_failed.connect(self.update_thread.quit)
self.update_checker.check_finished.connect(self.update_checker.deleteLater)
self.update_checker.check_failed.connect(self.update_checker.deleteLater)
self.update_thread.finished.connect(self.update_thread.deleteLater)
self.update_thread.start() self.update_thread.start()
def _on_update_check_finished(self, result): def _on_update_check_finished(self, result):
@@ -499,6 +505,14 @@ class VkChatManager(QMainWindow):
f"Доступная версия: {latest_version}\n\n" f"Доступная версия: {latest_version}\n\n"
"Открыть страницу загрузки?" "Открыть страницу загрузки?"
) )
release_notes = (result.get("release_notes") or "").strip()
if release_notes:
preview_lines = [line.strip() for line in release_notes.splitlines() if line.strip()]
preview_text = "\n".join(preview_lines[:8])
if len(preview_lines) > 8:
preview_text += "\n..."
message_box.setInformativeText(f"Что нового:\n{preview_text}")
message_box.setDetailedText(release_notes)
update_now_button = message_box.addButton("Обновить сейчас", QMessageBox.ButtonRole.AcceptRole) update_now_button = message_box.addButton("Обновить сейчас", QMessageBox.ButtonRole.AcceptRole)
download_button = message_box.addButton("Скачать", QMessageBox.ButtonRole.AcceptRole) download_button = message_box.addButton("Скачать", QMessageBox.ButtonRole.AcceptRole)
setup_button = None setup_button = None
@@ -975,12 +989,26 @@ class VkChatManager(QMainWindow):
self.token = token self.token = token
# Сохраняем и получаем корректный expiration_time (0 или будущее время) # Сохраняем и получаем корректный expiration_time (0 или будущее время)
self.token_expiration_time = token_store_save_token( try:
self.token, self.token_expiration_time = token_store_save_token(
TOKEN_FILE, self.token,
APP_DATA_DIR, TOKEN_FILE,
expires_in=expires_in, APP_DATA_DIR,
) expires_in=expires_in,
)
except Exception as e:
try:
expires_value = int(expires_in)
except (TypeError, ValueError):
expires_value = 0
self.token_expiration_time = (time.time() + expires_value) if expires_value > 0 else 0
self._log_event("token_store_save", str(e), level="WARN")
QMessageBox.warning(
self,
"Предупреждение",
"Не удалось безопасно сохранить токен на диске. "
"Текущая сессия активна, но после перезапуска потребуется повторная авторизация.",
)
self.token_input.setText(self.token[:50] + "...") self.token_input.setText(self.token[:50] + "...")
self.status_label.setText("Статус: авторизован") self.status_label.setText("Статус: авторизован")

View File

@@ -91,8 +91,8 @@ def save_token(token, token_file, app_data_dir, expires_in=0):
try: try:
stored_token = _encrypt_token(token) stored_token = _encrypt_token(token)
encrypted = True encrypted = True
except Exception: except Exception as exc:
pass raise RuntimeError("Failed to securely store token with DPAPI.") from exc
data = { data = {
"token": stored_token, "token": stored_token,

View File

@@ -102,6 +102,7 @@ def _extract_release_payload(release_data, repository_url, current_version):
latest_tag = release_data.get("tag_name") or release_data.get("name") or "" latest_tag = release_data.get("tag_name") or release_data.get("name") or ""
latest_version = latest_tag.lstrip("vV").strip() latest_version = latest_tag.lstrip("vV").strip()
html_url = release_data.get("html_url") or releases_url html_url = release_data.get("html_url") or releases_url
release_notes = (release_data.get("body") or "").strip()
assets = release_data.get("assets") or [] assets = release_data.get("assets") or []
download_url = "" download_url = ""
download_name = "" download_name = ""
@@ -147,6 +148,7 @@ def _extract_release_payload(release_data, repository_url, current_version):
"current_version": current_version, "current_version": current_version,
"latest_tag": latest_tag, "latest_tag": latest_tag,
"release_url": html_url, "release_url": html_url,
"release_notes": release_notes,
"download_url": download_url, "download_url": download_url,
"download_name": download_name, "download_name": download_name,
"installer_url": installer_url, "installer_url": installer_url,