gajim3/gajim/common/passwords.py

156 lines
5.4 KiB
Python

# Copyright (C) 2006 Gustavo J. A. M. Carneiro <gjcarneiro AT gmail.com>
# Nikos Kouremenos <kourem AT gmail.com>
# Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
# Copyright (C) 2007 Jean-Marie Traissard <jim AT lapin.org>
# Julien Pivotto <roidelapluie AT gmail.com>
# Copyright (C) 2008 Stephan Erb <steve-e AT h3c.de>
# Copyright (c) 2009 Thorsten Glaser <t.glaser AT tarent.de>
#
# 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 <http://www.gnu.org/licenses/>.
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__) == "<class '" +k_name +"'>",
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)