~didrocks/ubuntuone-client/dont-suffer-zg-crash

« back to all changes in this revision

Viewing changes to ubuntuone/platform/linux/credentials.py

  • Committer: Bazaar Package Importer
  • Author(s): Rodney Dawes
  • Date: 2011-02-11 16:18:11 UTC
  • mfrom: (1.1.44 upstream)
  • Revision ID: james.westby@ubuntu.com-20110211161811-lbelxu332e8r2dov
Tags: 1.5.4-0ubuntu1
* New upstream release.
  - Files still get downloaded from unsubscribed folder (LP: #682878)
  - Add subscription capabilities to shares (LP: #708335)
  - Nautilus offers Publish option within other's shares (LP: #712674)
  - Shares dir name may not be unique (LP: #715776)
  - Send a notification when new Volume is available (LP: #702055)
  - Add messaging menu entry for new Volumes (LP: #702075)
  - Aggregate notifications for completed operations (LP: #702128)
  - Send a notification for new Share offers (LP: #702138)
  - Add messaging menu entry for new Share offers (LP: #702144)
* Remove ubuntuone-client-tools as u1sync has been moved out.
* Simplify python package as we don't have multiple python packages now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
#
 
3
# Author: Natalia B. Bidart <natalia.bidart@canonical.com>
 
4
#
 
5
# Copyright 2010 Canonical Ltd.
 
6
#
 
7
# This program is free software: you can redistribute it and/or modify it
 
8
# under the terms of the GNU General Public License version 3, as published
 
9
# by the Free Software Foundation.
 
10
#
 
11
# This program is distributed in the hope that it will be useful, but
 
12
# WITHOUT ANY WARRANTY; without even the implied warranties of
 
13
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
14
# PURPOSE.  See the GNU General Public License for more details.
 
15
#
 
16
# You should have received a copy of the GNU General Public License along
 
17
# with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
 
 
19
"""Ubuntu One credentials management dbus service."""
 
20
 
 
21
import os
 
22
import sys
 
23
 
 
24
import dbus.service
 
25
import gettext
 
26
import ubuntu_sso
 
27
 
 
28
from ubuntu_sso.credentials import (HELP_TEXT_KEY, PING_URL_KEY, TC_URL_KEY,
 
29
    WINDOW_ID_KEY)
 
30
 
 
31
from ubuntuone.logger import (basic_formatter, logging,
 
32
    CustomRotatingFileHandler, LOGFOLDER)
 
33
from ubuntuone.clientdefs import GETTEXT_PACKAGE
 
34
 
 
35
 
 
36
Q_ = lambda string: gettext.dgettext(GETTEXT_PACKAGE, string)
 
37
NO_OP = lambda *args, **kwargs: None
 
38
TIMEOUT_INTERVAL = 500
 
39
 
 
40
LOG_LEVEL = logging.DEBUG
 
41
path = os.path.join(LOGFOLDER, 'credentials.log')
 
42
MAIN_HANDLER = CustomRotatingFileHandler(path)
 
43
MAIN_HANDLER.setFormatter(basic_formatter)
 
44
MAIN_HANDLER.setLevel(LOG_LEVEL)
 
45
 
 
46
logger = logging.getLogger("ubuntuone.credentials")
 
47
logger.setLevel(LOG_LEVEL)
 
48
logger.addHandler(MAIN_HANDLER)
 
49
 
 
50
if os.environ.get('DEBUG'):
 
51
    debug_handler = logging.StreamHandler(sys.stderr)
 
52
    debug_handler.setFormatter(basic_formatter)
 
53
    debug_handler.setLevel(LOG_LEVEL)
 
54
    logger.addHandler(debug_handler)
 
55
 
 
56
# constants
 
57
DBUS_BUS_NAME = "com.ubuntuone.Credentials"
 
58
DBUS_CREDENTIALS_PATH = "/credentials"
 
59
DBUS_CREDENTIALS_IFACE = "com.ubuntuone.CredentialsManagement"
 
60
 
 
61
APP_NAME = "Ubuntu One"
 
62
TC_URL = "https://one.ubuntu.com/terms/"
 
63
PING_URL = "https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/"
 
64
DESCRIPTION = Q_('Ubuntu One requires an Ubuntu Single Sign On (SSO) account. '
 
65
                 'This process will allow you to create a new account, '
 
66
                 'if you do not yet have one.')
 
67
 
 
68
 
 
69
class CredentialsManagement(dbus.service.Object):
 
70
    """DBus object that manages Ubuntu One credentials."""
 
71
 
 
72
    def __init__(self, timeout_func=lambda *a: None,
 
73
                 shutdown_func=lambda *a: None, *args, **kwargs):
 
74
        super(CredentialsManagement, self).__init__(*args, **kwargs)
 
75
        self._ref_count = 0
 
76
        self.timeout_func = timeout_func
 
77
        self.shutdown_func = shutdown_func
 
78
 
 
79
        self.sso_match = None
 
80
        self.sso_proxy = self._get_sso_proxy()
 
81
 
 
82
    def _signal_handler(self, *args, **kwargs):
 
83
        """Generic signal handler."""
 
84
        member = kwargs.get('member', None)
 
85
        app_name = args[0] if len(args) > 0 else None
 
86
        logger.debug('Handling DBus signal for member: %r, app_name: %r.',
 
87
                     member, app_name)
 
88
 
 
89
        if app_name != APP_NAME:
 
90
            logger.info('Received %r but app_name %r does not match %r, ' \
 
91
                        'exiting.', member, app_name, APP_NAME)
 
92
            return
 
93
 
 
94
        sig = getattr(self, member)
 
95
 
 
96
        if member in ('CredentialsFound', 'CredentialsError'):
 
97
            # this are the only signals that will forward the parameter
 
98
            logger.info('%r', member)
 
99
            arg = args[1]
 
100
            sig(arg)
 
101
        else:
 
102
            sig()
 
103
 
 
104
    def _get_sso_proxy(self):
 
105
        """Get the SSO dbus proxy."""
 
106
        bus = dbus.SessionBus()
 
107
        # register signal handlers for each kind of error
 
108
        self.sso_match = bus.add_signal_receiver(self._signal_handler,
 
109
                            member_keyword='member',
 
110
                            dbus_interface=ubuntu_sso.DBUS_CREDENTIALS_IFACE)
 
111
        try:
 
112
            obj = bus.get_object(ubuntu_sso.DBUS_BUS_NAME,
 
113
                                 ubuntu_sso.DBUS_CREDENTIALS_PATH,
 
114
                                 follow_name_owner_changes=True)
 
115
            proxy = dbus.Interface(obj, ubuntu_sso.DBUS_CREDENTIALS_IFACE)
 
116
        except:
 
117
            logger.exception('get_sso_proxy:')
 
118
            raise
 
119
 
 
120
        return proxy
 
121
 
 
122
    def _get_ref_count(self):
 
123
        """Get value of ref_count."""
 
124
        logger.debug('ref_count is %r.', self._ref_count)
 
125
        return self._ref_count
 
126
 
 
127
    def _set_ref_count(self, new_value):
 
128
        """Set a new value to ref_count."""
 
129
        logger.debug('ref_count is %r, changing value to %r.',
 
130
                     self._ref_count, new_value)
 
131
        if new_value < 0:
 
132
            self._ref_count = 0
 
133
            msg = 'Attempting to decrease ref_count to a negative value (%r).'
 
134
            logger.warning(msg, new_value)
 
135
        else:
 
136
            self._ref_count = new_value
 
137
 
 
138
        if self._ref_count == 0:
 
139
            self.timeout_func(TIMEOUT_INTERVAL, self.shutdown_func)
 
140
 
 
141
    ref_count = property(fget=_get_ref_count, fset=_set_ref_count)
 
142
 
 
143
    # Operator not preceded by a space (fails with dbus decorators)
 
144
    # pylint: disable=C0322
 
145
 
 
146
    @dbus.service.signal(DBUS_CREDENTIALS_IFACE)
 
147
    def AuthorizationDenied(self):
 
148
        """Signal thrown when the user denies the authorization."""
 
149
        self.ref_count -= 1
 
150
        logger.info('%s: emitting AuthorizationDenied.',
 
151
                    self.__class__.__name__)
 
152
 
 
153
    @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='a{ss}')
 
154
    def CredentialsFound(self, credentials):
 
155
        """Signal thrown when the credentials are found."""
 
156
        self.ref_count -= 1
 
157
        logger.info('%s: emitting CredentialsFound.',
 
158
                    self.__class__.__name__)
 
159
 
 
160
    @dbus.service.signal(DBUS_CREDENTIALS_IFACE)
 
161
    def CredentialsNotFound(self):
 
162
        """Signal thrown when the credentials are not found."""
 
163
        self.ref_count -= 1
 
164
        logger.info('%s: emitting CredentialsNotFound.',
 
165
                    self.__class__.__name__)
 
166
 
 
167
    @dbus.service.signal(DBUS_CREDENTIALS_IFACE)
 
168
    def CredentialsCleared(self):
 
169
        """Signal thrown when the credentials were cleared."""
 
170
        self.ref_count -= 1
 
171
        logger.info('%s: emitting CredentialsCleared.',
 
172
                    self.__class__.__name__)
 
173
 
 
174
    @dbus.service.signal(DBUS_CREDENTIALS_IFACE)
 
175
    def CredentialsStored(self):
 
176
        """Signal thrown when the credentials were cleared."""
 
177
        self.ref_count -= 1
 
178
        logger.info('%s: emitting CredentialsStored.',
 
179
                    self.__class__.__name__)
 
180
 
 
181
    @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='a{ss}')
 
182
    def CredentialsError(self, error_dict):
 
183
        """Signal thrown when there is a problem getting the credentials."""
 
184
        self.ref_count -= 1
 
185
        logger.error('%s: emitting CredentialsError with error_dict %r.',
 
186
                     self.__class__.__name__, error_dict)
 
187
 
 
188
    @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE,
 
189
                         async_callbacks=("reply_handler", "error_handler"))
 
190
    def find_credentials(self, reply_handler=NO_OP, error_handler=NO_OP):
 
191
        """Ask the Ubuntu One credentials."""
 
192
        self.ref_count += 1
 
193
        self.sso_proxy.find_credentials(APP_NAME, {},
 
194
            reply_handler=reply_handler, error_handler=error_handler)
 
195
 
 
196
 
 
197
    @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE,
 
198
                         async_callbacks=("reply_handler", "error_handler"))
 
199
    def clear_credentials(self, reply_handler=NO_OP, error_handler=NO_OP):
 
200
        """Clear the Ubuntu One credentials."""
 
201
        self.ref_count += 1
 
202
        self.sso_proxy.clear_credentials(APP_NAME, {},
 
203
            reply_handler=reply_handler, error_handler=error_handler)
 
204
 
 
205
    @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE,
 
206
                         in_signature='a{ss}',
 
207
                         async_callbacks=("reply_handler", "error_handler"))
 
208
    def store_credentials(self, credentials,
 
209
                          reply_handler=NO_OP, error_handler=NO_OP):
 
210
        """Store the token for Ubuntu One application."""
 
211
        self.ref_count += 1
 
212
        self.sso_proxy.store_credentials(APP_NAME, credentials,
 
213
            reply_handler=reply_handler, error_handler=error_handler)
 
214
 
 
215
    @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE,
 
216
                         async_callbacks=("reply_handler", "error_handler"))
 
217
    def register(self, reply_handler=NO_OP, error_handler=NO_OP):
 
218
        """Get credentials if found else prompt to register to Ubuntu One."""
 
219
        self.ref_count += 1
 
220
        params = {HELP_TEXT_KEY: DESCRIPTION, TC_URL_KEY: TC_URL,
 
221
                  PING_URL_KEY: PING_URL, WINDOW_ID_KEY: '0'}
 
222
        self.sso_proxy.register(APP_NAME, params,
 
223
            reply_handler=reply_handler, error_handler=error_handler)
 
224
 
 
225
    @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE,
 
226
                         async_callbacks=("reply_handler", "error_handler"))
 
227
    def login(self, reply_handler=NO_OP, error_handler=NO_OP):
 
228
        """Get credentials if found else prompt to login to Ubuntu One."""
 
229
        self.register(reply_handler, error_handler)
 
230
 
 
231
    @dbus.service.method(dbus_interface=DBUS_CREDENTIALS_IFACE,
 
232
                         async_callbacks=("reply_handler", "error_handler"))
 
233
    def shutdown(self, reply_handler=NO_OP, error_handler=NO_OP):
 
234
        """Disconnect signals from SSO backend."""
 
235
        bus = dbus.SessionBus()
 
236
        try:
 
237
            bus.remove_signal_receiver(self.sso_match, member_keyword='member',
 
238
                dbus_interface=ubuntu_sso.DBUS_CREDENTIALS_IFACE)
 
239
        except Exception, e:
 
240
            error_handler(e)
 
241
        else:
 
242
            reply_handler()