1
0

fix: prevent PluginsDialog from getting in bad state

If the plugin file got already deleted while being in the installation
dialog, trying to delete it again will raise an exception.
This is fixed by catching the exception.

If the user tries to install an external plugin that is already
installed, and then closes the PluginDialog, the PluginsDialog will
get into a bad state, throwing an exeption when opening it. This
happens because the add_plugin_dialog deletes the zipfile if the
user closes or cancels the installation dialog.
This is fixed by checking if the plugin is already existing,
instead of trying to install an already existing plugin.
This commit is contained in:
f321x
2025-04-28 16:55:21 +02:00
parent 4a8590077e
commit 1cce216c1f
2 changed files with 17 additions and 4 deletions

View File

@@ -7,6 +7,7 @@ from PyQt6.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QWidg
from PyQt6.QtCore import Qt
from electrum.i18n import _
from electrum.logging import get_logger
from .util import WindowModalDialog, Buttons, CloseButton, WWLabel, insert_spaces, MessageBoxMixin, EnterButton
from .util import read_QIcon_from_bytes, IconLabel
@@ -88,7 +89,7 @@ class PluginDialog(WindowModalDialog):
_('Settings'),
partial(p.settings_dialog, self))
buttons.insert(1, settings_button)
# add buttonss
# add buttons
vbox.addLayout(Buttons(*buttons))
def do_toggle(self):
@@ -150,6 +151,7 @@ class PluginStatusButton(QPushButton):
class PluginsDialog(WindowModalDialog, MessageBoxMixin):
_logger = get_logger(__name__)
def __init__(self, config: 'SimpleConfig', plugins:'Plugins', *, gui_object: Optional['ElectrumGui'] = None):
WindowModalDialog.__init__(self, None, _('Electrum Plugins'))
@@ -264,7 +266,10 @@ class PluginsDialog(WindowModalDialog, MessageBoxMixin):
self.show_error(f"{e}")
success = False
if not success:
os.unlink(path)
try:
os.unlink(path)
except FileNotFoundError:
self._logger.debug("", exc_info=True)
def add_plugin_dialog(self):
pubkey, salt = self.plugins.get_pubkey_bytes()
@@ -276,6 +281,9 @@ class PluginsDialog(WindowModalDialog, MessageBoxMixin):
return
plugins_dir = self.plugins.get_external_plugin_dir()
path = os.path.join(plugins_dir, os.path.basename(filename))
if os.path.exists(path):
self.show_warning(_('Plugin already installed.'))
return
shutil.copyfile(filename, path)
try:
success = self.add_external_plugin(path)
@@ -283,7 +291,10 @@ class PluginsDialog(WindowModalDialog, MessageBoxMixin):
self.show_error(f"{e}")
success = False
if not success:
os.unlink(path)
try:
os.unlink(path)
except FileNotFoundError:
self._logger.debug("", exc_info=True)
def add_external_plugin(self, path):
manifest = self.plugins.read_manifest(path)

View File

@@ -246,10 +246,12 @@ class Plugins(DaemonThread):
os.mkdir(pkg_path)
return pkg_path
async def download_external_plugin(self, url):
async def download_external_plugin(self, url: str) -> str:
filename = os.path.basename(urlparse(url).path)
pkg_path = self.get_external_plugin_dir()
path = os.path.join(pkg_path, filename)
if os.path.exists(path):
raise FileExistsError(f"Plugin {filename} already exists at {path}")
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
if resp.status == 200: