Philipp Hörist pushed to branch master at gajim / gajim
Commits:
-
cb89f598
by lovetox at 2022-07-05T21:37:01+02:00
5 changed files:
- gajim/common/application.py
- gajim/common/passwords.py
- gajim/gtk/accounts.py
- gajim/gtk/features.py
- gajim/gtk/password_dialog.py
Changes:
| ... | ... | @@ -36,6 +36,7 @@ |
| 36 | 36 | from gajim.common import ged
|
| 37 | 37 | from gajim.common import configpaths
|
| 38 | 38 | from gajim.common import logging_helpers
|
| 39 | +from gajim.common import passwords
|
|
| 39 | 40 | from gajim.common.dbus import logind
|
| 40 | 41 | from gajim.common.events import AccountDisonnected
|
| 41 | 42 | from gajim.common.events import AllowGajimUpdateCheck
|
| ... | ... | @@ -61,6 +62,8 @@ def _init_core(self) -> None: |
| 61 | 62 | app.detect_dependencies()
|
| 62 | 63 | configpaths.create_paths()
|
| 63 | 64 | |
| 65 | + passwords.init()
|
|
| 66 | + |
|
| 64 | 67 | app.settings = Settings()
|
| 65 | 68 | app.settings.init()
|
| 66 | 69 |
| ... | ... | @@ -23,6 +23,7 @@ |
| 23 | 23 | from __future__ import annotations
|
| 24 | 24 | |
| 25 | 25 | from typing import Optional
|
| 26 | +from typing import cast
|
|
| 26 | 27 | |
| 27 | 28 | import logging
|
| 28 | 29 | |
| ... | ... | @@ -31,21 +32,34 @@ |
| 31 | 32 | from gajim.common import app
|
| 32 | 33 | |
| 33 | 34 | __all__ = [
|
| 35 | + 'init',
|
|
| 36 | + 'is_keyring_available',
|
|
| 34 | 37 | 'get_password',
|
| 35 | 38 | 'save_password',
|
| 36 | 39 | 'delete_password'
|
| 37 | 40 | ]
|
| 38 | 41 | |
| 39 | -log = logging.getLogger('gajim.password')
|
|
| 42 | +log = logging.getLogger('gajim.c.passwords')
|
|
| 40 | 43 | |
| 41 | -backends = keyring.backend.get_all_keyring()
|
|
| 42 | -for backend in backends:
|
|
| 43 | - log.info('Found keyring backend: %s', backend)
|
|
| 44 | 44 | |
| 45 | -keyring_backend = keyring.get_keyring()
|
|
| 46 | -log.info('Select %s backend', keyring_backend)
|
|
| 45 | +class Interface:
|
|
| 46 | + def __init__(self):
|
|
| 47 | + self.backend = cast(keyring.backend.KeyringBackend, None)
|
|
| 48 | + self._is_keyring_available = False
|
|
| 47 | 49 | |
| 48 | -KEYRING_AVAILABLE = keyring.core.recommended(keyring_backend)
|
|
| 50 | + @property
|
|
| 51 | + def is_keyring_available(self):
|
|
| 52 | + return self._is_keyring_available
|
|
| 53 | + |
|
| 54 | + def init(self) -> None:
|
|
| 55 | + backends = keyring.backend.get_all_keyring()
|
|
| 56 | + for backend in backends:
|
|
| 57 | + log.info('Found keyring backend: %s', backend)
|
|
| 58 | + |
|
| 59 | + self.backend = keyring.get_keyring()
|
|
| 60 | + log.info('Select %s backend', self.backend)
|
|
| 61 | + |
|
| 62 | + self._is_keyring_available = keyring.core.recommended(self.backend)
|
|
| 49 | 63 | |
| 50 | 64 | |
| 51 | 65 | class SecretPasswordStorage:
|
| ... | ... | @@ -55,13 +69,13 @@ class SecretPasswordStorage: |
| 55 | 69 | |
| 56 | 70 | @staticmethod
|
| 57 | 71 | def save_password(account_name: str, password: str) -> bool:
|
| 58 | - if not KEYRING_AVAILABLE:
|
|
| 72 | + if not is_keyring_available():
|
|
| 59 | 73 | log.warning('No recommended keyring backend available.'
|
| 60 | 74 | 'Passwords cannot be stored.')
|
| 61 | 75 | return True
|
| 62 | 76 | try:
|
| 63 | 77 | log.info('Save password to keyring')
|
| 64 | - keyring_backend.set_password('gajim', account_name, password)
|
|
| 78 | + _interface.backend.set_password('gajim', account_name, password)
|
|
| 65 | 79 | return True
|
| 66 | 80 | except Exception:
|
| 67 | 81 | log.exception('Save password failed')
|
| ... | ... | @@ -69,25 +83,28 @@ def save_password(account_name: str, password: str) -> bool: |
| 69 | 83 | |
| 70 | 84 | @staticmethod
|
| 71 | 85 | def get_password(account_name: str) -> Optional[str]:
|
| 72 | - log.info('Request password from keyring')
|
|
| 73 | - if not KEYRING_AVAILABLE:
|
|
| 86 | + if not is_keyring_available():
|
|
| 74 | 87 | return
|
| 88 | + |
|
| 89 | + log.info('Request password from keyring')
|
|
| 90 | + |
|
| 75 | 91 | try:
|
| 76 | 92 | # For security reasons remove clear-text password
|
| 77 | 93 | ConfigPasswordStorage.delete_password(account_name)
|
| 78 | - return keyring_backend.get_password('gajim', account_name)
|
|
| 94 | + return _interface.backend.get_password('gajim', account_name)
|
|
| 79 | 95 | except Exception:
|
| 80 | 96 | log.exception('Request password failed')
|
| 81 | 97 | return
|
| 82 | 98 | |
| 83 | 99 | @staticmethod
|
| 84 | 100 | def delete_password(account_name: str) -> None:
|
| 85 | - log.info('Remove password from keyring')
|
|
| 86 | - if not KEYRING_AVAILABLE:
|
|
| 101 | + if not is_keyring_available():
|
|
| 87 | 102 | return
|
| 88 | 103 | |
| 104 | + log.info('Remove password from keyring')
|
|
| 105 | + |
|
| 89 | 106 | try:
|
| 90 | - return keyring_backend.delete_password('gajim', account_name)
|
|
| 107 | + return _interface.backend.delete_password('gajim', account_name)
|
|
| 91 | 108 | except keyring.errors.PasswordDeleteError as error:
|
| 92 | 109 | log.warning('Removing password failed: %s', error)
|
| 93 | 110 | except Exception:
|
| ... | ... | @@ -113,6 +130,14 @@ def delete_password(account_name: str) -> None: |
| 113 | 130 | app.settings.set_account_setting(account_name, 'password', '')
|
| 114 | 131 | |
| 115 | 132 | |
| 133 | +def init() -> None:
|
|
| 134 | + _interface.init()
|
|
| 135 | + |
|
| 136 | + |
|
| 137 | +def is_keyring_available() -> bool:
|
|
| 138 | + return _interface.is_keyring_available
|
|
| 139 | + |
|
| 140 | + |
|
| 116 | 141 | def get_password(account_name: str) -> Optional[str]:
|
| 117 | 142 | if app.settings.get('use_keyring'):
|
| 118 | 143 | return SecretPasswordStorage.get_password(account_name)
|
| ... | ... | @@ -138,3 +163,6 @@ def delete_password(account_name: str) -> None: |
| 138 | 163 | if app.settings.get('use_keyring'):
|
| 139 | 164 | return SecretPasswordStorage.delete_password(account_name)
|
| 140 | 165 | return ConfigPasswordStorage.delete_password(account_name)
|
| 166 | + |
|
| 167 | + |
|
| 168 | +_interface = Interface() |
| ... | ... | @@ -1084,7 +1084,7 @@ def __init__(self, account: str, parent: Gtk.Window) -> None: |
| 1084 | 1084 | SettingType.ACCOUNT_CONFIG,
|
| 1085 | 1085 | 'savepass',
|
| 1086 | 1086 | enabled_func=(lambda: not app.settings.get('use_keyring') or
|
| 1087 | - passwords.KEYRING_AVAILABLE)),
|
|
| 1087 | + passwords.is_keyring_available())),
|
|
| 1088 | 1088 | |
| 1089 | 1089 | Setting(SettingKind.CHANGEPASSWORD,
|
| 1090 | 1090 | _('Change Password'),
|
| ... | ... | @@ -29,6 +29,7 @@ |
| 29 | 29 | from gi.repository import Gdk
|
| 30 | 30 | |
| 31 | 31 | from gajim.common import app
|
| 32 | +from gajim.common import passwords
|
|
| 32 | 33 | from gajim.common.i18n import _
|
| 33 | 34 | |
| 34 | 35 | |
| ... | ... | @@ -125,7 +126,7 @@ def _get_features(self) -> list[Feature]: |
| 125 | 126 | _('No additional requirements'),
|
| 126 | 127 | notification_sounds_enabled),
|
| 127 | 128 | Feature(_('Secure Password Storage'),
|
| 128 | - self._some_keyring_available(),
|
|
| 129 | + passwords.is_keyring_available(),
|
|
| 129 | 130 | _('Enables Gajim to store Passwords securely instead of '
|
| 130 | 131 | 'storing them in plaintext'),
|
| 131 | 132 | _('Requires: gnome-keyring or kwallet'),
|
| ... | ... | @@ -148,11 +149,6 @@ def _get_features(self) -> list[Feature]: |
| 148 | 149 | None)
|
| 149 | 150 | ]
|
| 150 | 151 | |
| 151 | - @staticmethod
|
|
| 152 | - def _some_keyring_available() -> bool:
|
|
| 153 | - from gajim.common import passwords
|
|
| 154 | - return passwords.KEYRING_AVAILABLE
|
|
| 155 | - |
|
| 156 | 152 | @staticmethod
|
| 157 | 153 | def _idle_available() -> bool:
|
| 158 | 154 | from gajim.common import idle
|
| ... | ... | @@ -18,10 +18,9 @@ |
| 18 | 18 | from gi.repository import Gdk
|
| 19 | 19 | |
| 20 | 20 | from gajim.common import app
|
| 21 | +from gajim.common import passwords
|
|
| 21 | 22 | from gajim.common.events import PasswordRequired
|
| 22 | 23 | from gajim.common.i18n import _
|
| 23 | -from gajim.common.passwords import save_password
|
|
| 24 | -from gajim.common.passwords import KEYRING_AVAILABLE
|
|
| 25 | 24 | |
| 26 | 25 | from .builder import get_builder
|
| 27 | 26 | |
| ... | ... | @@ -69,9 +68,12 @@ def _process_event(self) -> None: |
| 69 | 68 | 'jid': own_jid,
|
| 70 | 69 | 'account': account_name})
|
| 71 | 70 | self._ui.save_pass_checkbutton.show()
|
| 71 | + |
|
| 72 | + is_keyring_available = passwords.is_keyring_available()
|
|
| 72 | 73 | self._ui.save_pass_checkbutton.set_sensitive(
|
| 73 | - not app.settings.get('use_keyring') or KEYRING_AVAILABLE)
|
|
| 74 | - if not KEYRING_AVAILABLE:
|
|
| 74 | + not app.settings.get('use_keyring') or
|
|
| 75 | + is_keyring_available)
|
|
| 76 | + if not is_keyring_available:
|
|
| 75 | 77 | self._ui.keyring_hint.show()
|
| 76 | 78 | |
| 77 | 79 | def _on_ok(self, _button: Gtk.Button) -> None:
|
| ... | ... | @@ -81,7 +83,7 @@ def _on_ok(self, _button: Gtk.Button) -> None: |
| 81 | 83 | self.account,
|
| 82 | 84 | 'savepass',
|
| 83 | 85 | self._ui.save_pass_checkbutton.get_active())
|
| 84 | - save_password(self.account, password)
|
|
| 86 | + passwords.save_password(self.account, password)
|
|
| 85 | 87 | self._event.on_password(password)
|
| 86 | 88 | self.destroy()
|
| 87 | 89 |