Philipp Hörist pushed to branch master at gajim / gajim

Commits:

5 changed files:

Changes:

  • gajim/common/application.py
    ... ... @@ -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
     
    

  • gajim/common/passwords.py
    ... ... @@ -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()

  • gajim/gtk/accounts.py
    ... ... @@ -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'),
    

  • gajim/gtk/features.py
    ... ... @@ -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
    

  • gajim/gtk/password_dialog.py
    ... ... @@ -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