# Copyright (C) 2006 Gustavo J. A. M. Carneiro # Nikos Kouremenos # Copyright (C) 2006-2014 Yann Leboulanger # Copyright (C) 2007 Jean-Marie Traissard # Julien Pivotto # Copyright (C) 2008 Stephan Erb # Copyright (c) 2009 Thorsten Glaser # # This file is part of Gajim. # # Gajim is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; version 3 only. # # Gajim is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Gajim. If not, see . import logging import keyring import os from gajim.common import app __all__ = ['get_password', 'save_password'] log = logging.getLogger('gajim.password') from keyring.backends.SecretService import Keyring KEYRING_AVAILABLE = None backends = keyring.backend.get_all_keyring() if 'PYTHON_KEYRING_BACKEND' in os.environ and os.environ['PYTHON_KEYRING_BACKEND']: k_name=os.environ['PYTHON_KEYRING_BACKEND'] # 'keyring.backends.SecretService.Keyring' k_list = list(filter(lambda elt: repr(elt.__class__) == "", backends)) if k_list: keyring_backend = k_list[0] KEYRING_AVAILABLE = True log.info('Select PYTHON_KEYRING_BACKEND %s backend', keyring_backend) else: log.warn('Select PYTHON_KEYRING_BACKEND %s not found', k_name) if not KEYRING_AVAILABLE: for backend in backends: log.info('Found keyring backend: %s', backend) keyring_backend = keyring.get_keyring() KEYRING_AVAILABLE = any(keyring.core.recommended(backend) for backend in backends) log.info('Select %s backend', keyring_backend) class SecretPasswordStorage: """ Store password using Keyring """ @staticmethod def save_password(account_name, password, **kwargs): if not KEYRING_AVAILABLE: log.warning('No recommended keyring backend available.' 'Passwords cannot be stored.') return True if kwargs is None: kwargs = dict() kwargs["server"] = "xmpp" kwargs["type"] = "plaintext" kwargs["xdg:schema"] = "org.qt.keychain" try: log.info('Save password to keyring') keyring_backend.set_password('gajim', account_name, password, # these are added for qt compatability **kwargs ) return True except Exception: log.exception('Save password failed') return False @staticmethod def get_password(account_name): log.info('Request password from keyring') if not KEYRING_AVAILABLE: return try: # For security reasons remove clear-text password ConfigPasswordStorage.delete_password(account_name) return keyring_backend.get_password('gajim', account_name) except Exception: log.exception('Request password failed') return @staticmethod def delete_password(account_name): log.info('Remove password from keyring') if not KEYRING_AVAILABLE: return try: return keyring_backend.delete_password('gajim', account_name) except keyring.errors.PasswordDeleteError as error: log.warning('Removing password failed: %s', error) except Exception: log.exception('Removing password failed') class ConfigPasswordStorage: """ Store password directly in Gajim's config """ @staticmethod def get_password(account_name): return app.settings.get_account_setting(account_name, 'password') @staticmethod def save_password(account_name, password, **kwargs): app.settings.set_account_setting(account_name, 'password', password) return True @staticmethod def delete_password(account_name): app.settings.set_account_setting(account_name, 'password', '') return True def get_password(account_name): if app.settings.get('use_keyring'): return SecretPasswordStorage.get_password(account_name) return ConfigPasswordStorage.get_password(account_name) def save_password(account_name, password): if account_name in app.connections: app.connections[account_name].password = password if not app.settings.get_account_setting(account_name, 'savepass'): return True if app.settings.get('use_keyring'): user = app.get_account_label(account) # guessing return SecretPasswordStorage.save_password(account_name, password, user=user) return ConfigPasswordStorage.save_password(account_name, password) def delete_password(account_name): if account_name in app.connections: app.connections[account_name].password = None if app.settings.get('use_keyring'): return SecretPasswordStorage.delete_password(account_name) return ConfigPasswordStorage.delete_password(account_name)