security+robustness(py/gui): thread-safety, upload hardening, keyring
macro_manager: - All macro reads/writes guarded by a lock; macros.json written atomically (temp + fsync + os.replace). Commands are copied under the lock and executed outside it so wait/keyboard steps don't block other threads. - last_used disk writes debounced (>=5s) instead of a full rewrite per press. - Validate key/hotkey names against pyautogui.KEYBOARD_KEYS and clamp wait ms; invalid input is skipped/logged, not blindly executed. web_server: - WebSocket receive loop always disconnects (fixes dead-socket leak); broadcast prunes failed sockets. - POST /api/execute offloaded to a thread executor so a long macro no longer blocks the event loop. - Image upload hardened: 5MB cap (413), real-image validation via Pillow, server-generated name under macro_images/, returns a relative path only, cleans up on failure. gui: - Execute macros off the Qt main thread (signal back to status bar); debounce resizeEvent and only rebuild when the column count changes. - Relay password stored in the OS keyring when available (plaintext JSON blanked; graceful fallback if no backend); delete dialogs name the macro; honor the minimize-to-tray setting; surface save failures. - Add media/system keys (volume, play/pause, track nav) to the macro editor. - THEME gains shared danger/accent-hover colors; drop dead imports. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -123,7 +123,7 @@ class SettingsDialog(QDialog):
|
||||
color: white;
|
||||
}}
|
||||
QPushButton:hover {{
|
||||
background-color: #0096ff;
|
||||
background-color: {THEME['accent_hover']};
|
||||
}}
|
||||
""")
|
||||
save_btn.clicked.connect(self.save_settings)
|
||||
@@ -316,9 +316,15 @@ class SettingsDialog(QDialog):
|
||||
|
||||
self.settings_manager.set('relay.enabled', new_enabled)
|
||||
self.settings_manager.set('relay.server_url', new_url)
|
||||
self.settings_manager.set('relay.password', new_password)
|
||||
|
||||
self.settings_manager.save()
|
||||
# Store the password via the keyring-aware setter (also persists the
|
||||
# rest of the settings). Avoid writing the plaintext password to JSON.
|
||||
ok = self.settings_manager.set_relay_password(new_password)
|
||||
if not ok:
|
||||
QMessageBox.warning(
|
||||
self, "Save Warning",
|
||||
"Settings could not be fully saved to disk."
|
||||
)
|
||||
|
||||
if relay_changed:
|
||||
self.relay_settings_changed.emit()
|
||||
|
||||
Reference in New Issue
Block a user