1
# -*- coding: utf-8 -*-
3
# Copyright 2011-2012 Canonical Ltd.
4
# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros)
6
# This program is free software: you can redistribute it and/or modify it
7
# under the terms of the GNU General Public License version 3, as published
8
# by the Free Software Foundation.
10
# This program is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranties of
12
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13
# PURPOSE. See the GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License along
16
# with this program. If not, see <http://www.gnu.org/licenses/>.
18
# In addition, as a special exception, the copyright holders give
19
# permission to link the code of portions of this program with the
20
# OpenSSL library under certain conditions as described in each
21
# individual source file, and distribute linked combinations
23
# You must obey the GNU General Public License in all respects
24
# for all of the code used other than OpenSSL. If you modify
25
# file(s) with this exception, you may extend this exception to your
26
# version of the file(s), but you are not obligated to do so. If you
27
# do not wish to do so, delete this exception statement from your
28
# version. If you delete this exception statement from all source
29
# files in the program, then also delete it here.
31
"""Handle keys in the local kerying."""
33
from __future__ import unicode_literals
40
from urllib.parse import parse_qsl, quote, urlencode
42
from urllib import quote, urlencode
43
from urlparse import parse_qsl
45
from twisted.internet.defer import inlineCallbacks, returnValue
47
from ubuntuone.clientdefs import NAME
48
from ubuntuone.utils import compat
49
from ubuntuone.utils.txsecrets import SecretService
52
logger = logging.getLogger(__name__)
54
TOKEN_SEPARATOR = ' @ '
55
SEPARATOR_REPLACEMENT = ' AT '
59
"""Get the hostname, return the name as unicode."""
60
sys_encoding = sys.getfilesystemencoding()
61
hostname = socket.gethostname()
62
if isinstance(hostname, compat.binary_type):
63
return hostname.decode(sys_encoding)
67
def get_token_name(app_name):
68
"""Build the token name.. Return an unicode."""
69
computer_name = gethostname()
70
computer_name = computer_name.replace(TOKEN_SEPARATOR,
71
SEPARATOR_REPLACEMENT)
73
assert isinstance(computer_name, compat.text_type)
74
assert isinstance(computer_name, compat.text_type)
76
return TOKEN_SEPARATOR.join((app_name, computer_name))
79
class Keyring(object):
80
"""A Keyring for a given application name."""
83
"""Initialize this instance."""
84
self.service = SecretService()
86
def _get_keyring_attr(self, app_name):
87
"""Build the keyring attributes for this credentials."""
88
attr = {"key-type": "%s credentials" % NAME,
89
"token-name": get_token_name(app_name)}
93
def _find_keyring_item(self, app_name, attr=None):
94
"""Return the keyring item or None if not found."""
96
attr = self._get_keyring_attr(app_name)
97
logger.debug("Finding all items for app_name %r.", app_name)
98
items = yield self.service.search_items(attr)
100
# if no items found, return None
101
logger.debug("No items found!")
104
logger.debug("Returning first item found.")
105
returnValue(items[0])
108
def set_credentials(self, app_name, cred):
109
"""Set the credentials."""
110
# Creates the secret from the credentials
111
secret = urlencode(cred)
113
attr = self._get_keyring_attr(app_name)
114
# Add our credentials to the keyring
115
yield self.service.open_session()
116
collection = yield self.service.get_default_collection()
117
yield collection.create_item(app_name, attr, secret, True)
120
def get_credentials(self, app_name):
121
"""A deferred with the secret in a dictionary."""
122
# If we have no attributes, return None
123
logger.debug("Getting credentials for %r.", app_name)
124
yield self.service.open_session()
125
item = yield self._find_keyring_item(app_name)
127
logger.debug("Parsing secret.")
128
secret = yield item.get_value()
129
returnValue(dict(parse_qsl(secret)))
135
def delete_credentials(self, app_name):
136
"""Delete a set of credentials from the keyring."""
137
attr = self._get_keyring_attr(app_name)
138
# Add our credentials to the keyring
139
yield self.service.open_session()
140
collection = yield self.service.get_default_collection()
141
yield collection.create_item(app_name, attr, "secret!", True)
143
item = yield self._find_keyring_item(app_name)