| 1 | ## |
|---|
| 2 | ## Copyright (C) 2006 Gustavo J. A. M. Carneiro <gjcarneiro@gmail.com> |
|---|
| 3 | ## Copyright (C) 2006 Nikos Kouremenos <kourem@gmail.com> |
|---|
| 4 | ## |
|---|
| 5 | ## This program is free software; you can redistribute it and/or modify |
|---|
| 6 | ## it under the terms of the GNU General Public License as published |
|---|
| 7 | ## by the Free Software Foundation; version 2 only. |
|---|
| 8 | ## |
|---|
| 9 | ## This program is distributed in the hope that it will be useful, |
|---|
| 10 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 12 | ## GNU General Public License for more details. |
|---|
| 13 | ## |
|---|
| 14 | |
|---|
| 15 | __all__ = ['get_password', 'save_password'] |
|---|
| 16 | |
|---|
| 17 | from common import gajim |
|---|
| 18 | |
|---|
| 19 | USER_HAS_GNOMEKEYRING = False |
|---|
| 20 | USER_USES_GNOMEKEYRING = False |
|---|
| 21 | gnomekeyring = None |
|---|
| 22 | |
|---|
| 23 | class PasswordStorage(object): |
|---|
| 24 | def get_password(self, account_name): |
|---|
| 25 | raise NotImplementedError |
|---|
| 26 | def save_password(self, account_name, password): |
|---|
| 27 | raise NotImplementedError |
|---|
| 28 | |
|---|
| 29 | |
|---|
| 30 | class SimplePasswordStorage(PasswordStorage): |
|---|
| 31 | def get_password(self, account_name): |
|---|
| 32 | passwd = gajim.config.get_per('accounts', account_name, 'password') |
|---|
| 33 | if passwd and passwd.startswith('gnomekeyring:'): |
|---|
| 34 | return None # this is not a real password, it's a gnome keyring token |
|---|
| 35 | else: |
|---|
| 36 | return passwd |
|---|
| 37 | |
|---|
| 38 | def save_password(self, account_name, password): |
|---|
| 39 | gajim.config.set_per('accounts', account_name, 'password', password) |
|---|
| 40 | gajim.connections[account_name].password = password |
|---|
| 41 | |
|---|
| 42 | |
|---|
| 43 | class GnomePasswordStorage(PasswordStorage): |
|---|
| 44 | def __init__(self): |
|---|
| 45 | # self.keyring = gnomekeyring.get_default_keyring_sync() |
|---|
| 46 | |
|---|
| 47 | ## above line commented and code below inserted as workaround |
|---|
| 48 | ## for the bug http://bugzilla.gnome.org/show_bug.cgi?id=363019 |
|---|
| 49 | self.keyring = "default" |
|---|
| 50 | try: |
|---|
| 51 | gnomekeyring.create_sync(self.keyring, None) |
|---|
| 52 | except gnomekeyring.AlreadyExistsError: |
|---|
| 53 | pass |
|---|
| 54 | |
|---|
| 55 | def get_password(self, account_name): |
|---|
| 56 | conf = gajim.config.get_per('accounts', account_name, 'password') |
|---|
| 57 | if conf is None: |
|---|
| 58 | return None |
|---|
| 59 | try: |
|---|
| 60 | unused, auth_token = conf.split('gnomekeyring:') |
|---|
| 61 | auth_token = int(auth_token) |
|---|
| 62 | except ValueError: |
|---|
| 63 | password = conf |
|---|
| 64 | ## migrate the password over to keyring |
|---|
| 65 | try: |
|---|
| 66 | self.save_password(account_name, password, update=False) |
|---|
| 67 | except gnomekeyring.NoKeyringDaemonError: |
|---|
| 68 | ## no keyring daemon: in the future, stop using it |
|---|
| 69 | set_storage(SimplePasswordStorage()) |
|---|
| 70 | return password |
|---|
| 71 | try: |
|---|
| 72 | return gnomekeyring.item_get_info_sync(self.keyring, |
|---|
| 73 | auth_token).get_secret() |
|---|
| 74 | except gnomekeyring.DeniedError: |
|---|
| 75 | return None |
|---|
| 76 | except gnomekeyring.NoKeyringDaemonError: |
|---|
| 77 | ## no keyring daemon: in the future, stop using it |
|---|
| 78 | set_storage(SimplePasswordStorage()) |
|---|
| 79 | return None |
|---|
| 80 | |
|---|
| 81 | def save_password(self, account_name, password, update=True): |
|---|
| 82 | display_name = _('Gajim account %s') % account_name |
|---|
| 83 | attributes = dict(account_name=str(account_name), gajim=1) |
|---|
| 84 | try: |
|---|
| 85 | auth_token = gnomekeyring.item_create_sync( |
|---|
| 86 | self.keyring, gnomekeyring.ITEM_GENERIC_SECRET, |
|---|
| 87 | display_name, attributes, password, update) |
|---|
| 88 | except gnomekeyring.DeniedError: |
|---|
| 89 | set_storage(SimplePasswordStorage()) |
|---|
| 90 | storage.save_password(account_name, password) |
|---|
| 91 | return |
|---|
| 92 | token = 'gnomekeyring:%i' % auth_token |
|---|
| 93 | gajim.config.set_per('accounts', account_name, 'password', token) |
|---|
| 94 | if gajim.connections.has_key(account_name): |
|---|
| 95 | gajim.connections[account_name].password = password |
|---|
| 96 | |
|---|
| 97 | storage = None |
|---|
| 98 | def get_storage(): |
|---|
| 99 | global storage |
|---|
| 100 | if storage is None: # None is only in first time get_storage is called |
|---|
| 101 | if gajim.config.get('use_gnomekeyring'): |
|---|
| 102 | global gnomekeyring |
|---|
| 103 | try: |
|---|
| 104 | import gnomekeyring |
|---|
| 105 | except ImportError: |
|---|
| 106 | pass |
|---|
| 107 | else: |
|---|
| 108 | global USER_HAS_GNOMEKEYRING |
|---|
| 109 | global USER_USES_GNOMEKEYRING |
|---|
| 110 | USER_HAS_GNOMEKEYRING = True |
|---|
| 111 | if gnomekeyring.is_available(): |
|---|
| 112 | USER_USES_GNOMEKEYRING = True |
|---|
| 113 | else: |
|---|
| 114 | USER_USES_GNOMEKEYRING = False |
|---|
| 115 | if USER_USES_GNOMEKEYRING: |
|---|
| 116 | try: |
|---|
| 117 | storage = GnomePasswordStorage() |
|---|
| 118 | except gnomekeyring.NoKeyringDaemonError: |
|---|
| 119 | storage = SimplePasswordStorage() |
|---|
| 120 | except gnomekeyring.DeniedError: |
|---|
| 121 | storage = SimplePasswordStorage() |
|---|
| 122 | else: |
|---|
| 123 | storage = SimplePasswordStorage() |
|---|
| 124 | return storage |
|---|
| 125 | |
|---|
| 126 | def set_storage(storage_): |
|---|
| 127 | global storage |
|---|
| 128 | storage = storage_ |
|---|
| 129 | |
|---|
| 130 | |
|---|
| 131 | def get_password(account_name): |
|---|
| 132 | return get_storage().get_password(account_name) |
|---|
| 133 | |
|---|
| 134 | def save_password(account_name, password): |
|---|
| 135 | return get_storage().save_password(account_name, password) |
|---|