Commit 3a6cfa69 authored by Stef Walter's avatar Stef Walter

Update the mock service to more closely mirror real secret service

parent 075ca76c
......@@ -789,6 +789,23 @@ gsecret_collection_create_finish (GAsyncResult *result,
return g_object_ref (closure->collection);
}
/**
* gsecret_collection_create_sync:
* @service: a secret service object
* @label: label for the new collection
* @alias: (allow-none): alias to assign to the collection
* @cancellable: optional cancellation object
* @error: location to place an error on failure
*
* Create a new collection.
* Delete this collection.
*
* This method may block indefinitely. The secret service may prompt the
* user. gsecret_service_prompt() will be used to handle any prompts that
* show up.
*
* Returns: whether the item was successfully deleted or not
*/
GSecretCollection *
gsecret_collection_create_sync (GSecretService *service,
const gchar *label,
......@@ -821,6 +838,21 @@ gsecret_collection_create_sync (GSecretService *service,
return collection;
}
/**
* gsecret_collection_delete:
* @self: a collection
* @cancellable: optional cancellation object
* @callback: called when the operation completes
* @user_data: data to pass to the callback
*
* Delete this collection.
*
* This method returns immediately and completes asynchronously. The secret
* service may prompt the user. gsecret_service_prompt() will be used to handle
* any prompts that show up.
*
* Returns: whether the item was successfully deleted or not
*/
void
gsecret_collection_delete (GSecretCollection *self,
GCancellable *cancellable,
......@@ -837,6 +869,16 @@ gsecret_collection_delete (GSecretCollection *self,
cancellable, callback, user_data);
}
/**
* gsecret_collection_delete_finish:
* @self: a collection
* @result: asynchronous result passed to the callback
* @error: location to place an error on failure
*
* Complete operation to delete this collection.
*
* Returns: whether the item was successfully deleted or not
*/
gboolean
gsecret_collection_delete_finish (GSecretCollection *self,
GAsyncResult *result,
......@@ -848,6 +890,20 @@ gsecret_collection_delete_finish (GSecretCollection *self,
return gsecret_service_delete_path_finish (self->pv->service, result, error);
}
/**
* gsecret_collection_delete_sync:
* @self: a collection
* @cancellable: optional cancellation object
* @error: location to place an error on failure
*
* Delete this collection.
*
* This method may block indefinitely. The secret service may prompt the
* user. gsecret_service_prompt() will be used to handle any prompts that
* show up.
*
* Returns: whether the item was successfully deleted or not
*/
gboolean
gsecret_collection_delete_sync (GSecretCollection *self,
GCancellable *cancellable,
......@@ -875,6 +931,16 @@ gsecret_collection_delete_sync (GSecretCollection *self,
return ret;
}
/**
* gsecret_collection_get_items:
* @self: a collection
*
* Get the list of items in this collection.
*
* Returns: (transfer full) (element-type GSecret.Item): a list of items,
* when done, the list should be freed with g_list_free, and each item should
* be released with g_object_unref()
*/
GList *
gsecret_collection_get_items (GSecretCollection *self)
{
......@@ -906,6 +972,14 @@ _gsecret_collection_find_item_instance (GSecretCollection *self,
return item;
}
/**
* gsecret_collection_get_label:
* @self: a collection
*
* Get the label of this collection.
*
* Returns: (transfer full): the label, which should be freed with g_free()
*/
gchar *
gsecret_collection_get_label (GSecretCollection *self)
{
......@@ -923,6 +997,18 @@ gsecret_collection_get_label (GSecretCollection *self)
return label;
}
/**
* gsecret_collection_set_label:
* @self: a collection
* @label: a new label
* @cancellable: optional cancellation object
* @callback: called when the operation completes
* @user_data: data to pass to the callback
*
* Set the label of this collection.
*
* This function returns immediately and completes asynchronously.
*/
void
gsecret_collection_set_label (GSecretCollection *self,
const gchar *label,
......@@ -939,6 +1025,16 @@ gsecret_collection_set_label (GSecretCollection *self,
cancellable, callback, user_data);
}
/**
* gsecret_collection_set_label_finish:
* @self: a collection
* @result: asynchronous result passed to callback
* @error: location to place error on failure
*
* Complete asynchronous operation to set the label of this collection.
*
* Returns: whether the change was successful or not
*/
gboolean
gsecret_collection_set_label_finish (GSecretCollection *self,
GAsyncResult *result,
......@@ -951,6 +1047,20 @@ gsecret_collection_set_label_finish (GSecretCollection *self,
result, error);
}
/**
* gsecret_collection_set_label_sync:
* @self: a collection
* @label: a new label
* @cancellable: optional cancellation object
* @error: location to place error on failure
*
* Set the label of this collection.
*
* This function may block indefinetely. Use the asynchronous version
* in user interface threads.
*
* Returns: whether the change was successful or not
*/
gboolean
gsecret_collection_set_label_sync (GSecretCollection *self,
const gchar *label,
......@@ -965,6 +1075,14 @@ gsecret_collection_set_label_sync (GSecretCollection *self,
cancellable, error);
}
/**
* gsecret_collection_get_locked:
* @self: a collection
*
* Get whether the collection is locked or not.
*
* Returns: whether the collection is locked or not
*/
gboolean
gsecret_collection_get_locked (GSecretCollection *self)
{
......@@ -982,6 +1100,15 @@ gsecret_collection_get_locked (GSecretCollection *self)
return locked;
}
/**
* gsecret_collection_get_created:
* @self: a collection
*
* Get the created date and time of the collection. The return value is
* the number of seconds since the unix epoch, January 1st 1970.
*
* Returns: the created date and time
*/
guint64
gsecret_collection_get_created (GSecretCollection *self)
{
......@@ -999,6 +1126,15 @@ gsecret_collection_get_created (GSecretCollection *self)
return created;
}
/**
* gsecret_collection_get_modified:
* @self: a collection
*
* Get the modified date and time of the collection. The return value is
* the number of seconds since the unix epoch, January 1st 1970.
*
* Returns: the modified date and time
*/
guint64
gsecret_collection_get_modified (GSecretCollection *self)
{
......
......@@ -195,7 +195,7 @@ handle_property_changed (GObject *object,
else if (g_str_equal (property_name, "Label"))
g_object_notify (object, "label");
else if (g_str_equal (property_name, "Schema"))
else if (g_str_equal (property_name, "Type"))
g_object_notify (object, "schema");
else if (g_str_equal (property_name, "Locked"))
......@@ -1084,8 +1084,9 @@ gsecret_item_get_schema (GSecretItem *self)
g_return_val_if_fail (GSECRET_IS_ITEM (self), NULL);
variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Schema");
g_return_val_if_fail (variant != NULL, NULL);
variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Type");
if (variant == NULL)
return NULL;
label = g_variant_dup_string (variant, NULL);
g_variant_unref (variant);
......
......@@ -312,6 +312,8 @@ on_prompt_dismissed (GObject *source,
g_variant_unref (retval);
if (closure->vanished)
g_clear_error (&error);
if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD))
g_clear_error (&error);
if (error != NULL) {
g_simple_async_result_take_error (res, error);
......
......@@ -77,7 +77,7 @@ request_open_session_aes (GSecretSession *session)
g_assert (session->publi == NULL);
/* Initialize our local parameters and values */
if (!egg_dh_default_params ("ietf-ike-grp-modp-1536",
if (!egg_dh_default_params ("ietf-ike-grp-modp-1024",
&session->prime, &base))
g_return_val_if_reached (NULL);
......
......@@ -119,7 +119,7 @@
<property name="Modified" type="t" access="read"/>
<property name="Schema" type="s" access="read"/>
<property name="Type" type="s" access="read"/>
<method name="Delete">
<arg name="Prompt" type="o" direction="out"/>
......
......@@ -7,11 +7,11 @@ import sys
service = mock.SecretService()
service.add_standard_objects()
collection = mock.SecretCollection(service, "to_delete", locked=False)
collection = mock.SecretCollection(service, "todelete", locked=False)
mock.SecretItem(collection, "item", attributes={ "number": "1", "string": "one", "even": "false" }, secret="uno")
mock.SecretItem(collection, "confirm", attributes={ "number": "2", "string": "two", "even": "true" }, secret="dos", confirm=True)
collection = mock.SecretCollection(service, "two_delete", locked=True)
collection = mock.SecretCollection(service, "twodelete", locked=True)
mock.SecretItem(collection, "locked", attributes={ "number": "3", "string": "three", "even": "false" }, secret="tres")
service.listen()
\ No newline at end of file
......@@ -7,11 +7,11 @@ import sys
service = mock.SecretService()
service.add_standard_objects()
collection = mock.SecretCollection(service, "lock_one", locked=False, confirm=False)
collection = mock.SecretCollection(service, "lockone", locked=False, confirm=False)
mock.SecretItem(collection, "item", attributes={ "number": "1", "string": "one", "even": "false" }, secret="uno")
mock.SecretItem(collection, "confirm", attributes={ "number": "2", "string": "two", "even": "true" }, secret="dos", confirm=True)
collection = mock.SecretCollection(service, "lock_prompt", locked=True, confirm=True)
collection = mock.SecretCollection(service, "lockprompt", locked=True, confirm=True)
mock.SecretItem(collection, "locked", attributes={ "number": "3", "string": "three", "even": "false" }, secret="tres")
service.listen()
\ No newline at end of file
......@@ -33,7 +33,7 @@ service = mock.SecretService()
service.add_standard_objects()
mock.SecretPrompt(service, None, "simple")
mock.SecretPrompt(service, None, "delay", delay=0.5)
mock.SecretPrompt(service, None, "delay", delay=0.1)
def prompt_callback():
return dbus.String("Special Result", variant_level=1)
mock.SecretPrompt(service, None, "result", action=prompt_callback)
......
......@@ -634,9 +634,9 @@ def decryptData(key, data, mode=AESModeOfOperation.modeOfOperation["CBC"]):
def generateRandomKey(keysize):
"""Generates a key from random data of length `keysize`.
The returned key is a string of bytes.
"""
if keysize not in (16, 24, 32):
emsg = 'Invalid keysize, %s. Should be one of (16, 24, 32).'
......
......@@ -17,7 +17,7 @@
# Some utility functions from tlslite which is public domain
# Written by Trevor Perrin <trevp at trevp.net>
# http://trevp.net/tlslite/
#
#
import math
import random
......@@ -26,10 +26,8 @@ PRIME = '\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC9\x0F\xDA\xA2\x21\x68\xC2\x34\xC4\xC
'\x29\x02\x4E\x08\x8A\x67\xCC\x74\x02\x0B\xBE\xA6\x3B\x13\x9B\x22\x51\x4A\x08\x79\x8E\x34\x04\xDD' \
'\xEF\x95\x19\xB3\xCD\x3A\x43\x1B\x30\x2B\x0A\x6D\xF2\x5F\x14\x37\x4F\xE1\x35\x6D\x6D\x51\xC2\x45' \
'\xE4\x85\xB5\x76\x62\x5E\x7E\xC6\xF4\x4C\x42\xE9\xA6\x37\xED\x6B\x0B\xFF\x5C\xB6\xF4\x06\xB7\xED' \
'\xEE\x38\x6B\xFB\x5A\x89\x9F\xA5\xAE\x9F\x24\x11\x7C\x4B\x1F\xE6\x49\x28\x66\x51\xEC\xE4\x5B\x3D' \
'\xC2\x00\x7C\xB8\xA1\x63\xBF\x05\x98\xDA\x48\x36\x1C\x55\xD3\x9A\x69\x16\x3F\xA8\xFD\x24\xCF\x5F' \
'\x83\x65\x5D\x23\xDC\xA3\xAD\x96\x1C\x62\xF3\x56\x20\x85\x52\xBB\x9E\xD5\x29\x07\x70\x96\x96\x6D' \
'\x67\x0C\x35\x4E\x4A\xBC\x98\x04\xF1\x74\x6C\x08\xCA\x23\x73\x27\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'
'\xEE\x38\x6B\xFB\x5A\x89\x9F\xA5\xAE\x9F\x24\x11\x7C\x4B\x1F\xE6\x49\x28\x66\x51\xEC\xE6\x53\x81' \
'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'
def num_bits(number):
if number == 0:
......
# Upstream Author: Zooko O'Whielacronx <zooko@zooko.com>
#
# Copyright:
#
# You may use this package under the GNU General Public License, version
# 2 or, at your option, any later version. You may use this package
# under the Transitive Grace Period Public Licence, version 1.0 or, at
# your option, any later version. (You may choose to use this package
# under the terms of either licence, at your option.) See the file
# COPYING.GPL for the terms of the GNU General Public License, version 2.
# See the file COPYING.TGPPL.html for the terms of the Transitive Grace
# Period Public Licence, version 1.0.
#
# The following licensing text applies to a subset of the Crypto++ source code
# which is included in the pycryptopp source tree under the "embeddedcryptopp"
# subdirectory. That embedded subset of the Crypto++ source code is not used
# when pycryptopp is built for Debian -- instead the --disable-embedded-cryptopp
# option to "setup.py build" is used to for pycryptopp to build against the
# system libcryptopp.
import hashlib, hmac
import math
from binascii import a2b_hex, b2a_hex
class HKDF(object):
def __init__(self, ikm, L, salt=None, info="", digestmod = None):
self.ikm = ikm
self.keylen = L
if digestmod is None:
digestmod = hashlib.sha256
if callable(digestmod):
self.digest_cons = digestmod
else:
self.digest_cons = lambda d='':digestmod.new(d)
self.hashlen = len(self.digest_cons().digest())
if salt is None:
self.salt = chr(0)*(self.hashlen)
else:
self.salt = salt
self.info = info
#extract PRK
def extract(self):
h = hmac.new(self.salt, self.ikm, self.digest_cons)
self.prk = h.digest()
return self.prk
#expand PRK
def expand(self):
N = math.ceil(float(self.keylen)/self.hashlen)
T = ""
temp = ""
i=0x01
'''while len(T)<2*self.keylen :
msg = temp
msg += self.info
msg += b2a_hex(chr(i))
h = hmac.new(self.prk, a2b_hex(msg), self.digest_cons)
temp = b2a_hex(h.digest())
i += 1
T += temp
'''
while len(T)<self.keylen :
msg = temp
msg += self.info
msg += chr(i)
h = hmac.new(self.prk, msg, self.digest_cons)
temp = h.digest()
i += 1
T += temp
self.okm = T[0:self.keylen]
return self.okm
def new(ikm, L, salt=None, info="", digestmod = None):
return HKDF(ikm, L,salt,info,digestmod)
def hkdf(ikm, length, salt=None, info=""):
hk = HKDF(ikm, length ,salt,info)
computedprk = hk.extract()
# Upstream Author: Zooko O'Whielacronx <zooko@zooko.com>
#
# Copyright:
#
# You may use this package under the GNU General Public License, version
# 2 or, at your option, any later version. You may use this package
# under the Transitive Grace Period Public Licence, version 1.0 or, at
# your option, any later version. (You may choose to use this package
# under the terms of either licence, at your option.) See the file
# COPYING.GPL for the terms of the GNU General Public License, version 2.
# See the file COPYING.TGPPL.html for the terms of the Transitive Grace
# Period Public Licence, version 1.0.
#
# The following licensing text applies to a subset of the Crypto++ source code
# which is included in the pycryptopp source tree under the "embeddedcryptopp"
# subdirectory. That embedded subset of the Crypto++ source code is not used
# when pycryptopp is built for Debian -- instead the --disable-embedded-cryptopp
# option to "setup.py build" is used to for pycryptopp to build against the
# system libcryptopp.
import hashlib, hmac
import math
from binascii import a2b_hex, b2a_hex
class HKDF(object):
def __init__(self, ikm, L, salt=None, info="", digestmod = None):
self.ikm = ikm
self.keylen = L
if digestmod is None:
digestmod = hashlib.sha256
if callable(digestmod):
self.digest_cons = digestmod
else:
self.digest_cons = lambda d='':digestmod.new(d)
self.hashlen = len(self.digest_cons().digest())
if salt is None:
self.salt = chr(0)*(self.hashlen)
else:
self.salt = salt
self.info = info
#extract PRK
def extract(self):
h = hmac.new(self.salt, self.ikm, self.digest_cons)
self.prk = h.digest()
return self.prk
#expand PRK
def expand(self):
N = math.ceil(float(self.keylen)/self.hashlen)
T = ""
temp = ""
i=0x01
'''while len(T)<2*self.keylen :
msg = temp
msg += self.info
msg += b2a_hex(chr(i))
h = hmac.new(self.prk, a2b_hex(msg), self.digest_cons)
temp = b2a_hex(h.digest())
i += 1
T += temp
'''
while len(T)<self.keylen :
msg = temp
msg += self.info
msg += chr(i)
h = hmac.new(self.prk, msg, self.digest_cons)
temp = h.digest()
i += 1
T += temp
self.okm = T[0:self.keylen]
return self.okm
def new(ikm, L, salt=None, info="", digestmod = None):
return HKDF(ikm, L,salt,info,digestmod)
def hkdf(ikm, length, salt=None, info=""):
hk = HKDF(ikm, length ,salt,info)
computedprk = hk.extract()
return hk.expand()
\ No newline at end of file
......@@ -44,15 +44,26 @@ class IsLocked(dbus.exceptions.DBusException):
def __init__(self, msg):
dbus.exceptions.DBusException.__init__(self, msg, name="org.freedesktop.Secret.Error.IsLocked")
unique_identifier = 0
def next_identifier(prefix='x'):
class NoSuchObject(dbus.exceptions.DBusException):
def __init__(self, msg):
dbus.exceptions.DBusException.__init__(self, msg, name="org.freedesktop.Secret.Error.NoSuchObject")
unique_identifier = 111
def next_identifier(prefix=''):
global unique_identifier
unique_identifier += 1
return "%s%d" % (prefix, unique_identifier)
def encode_identifier(value):
return "".join([(c.isalpha() or c.isdigit()) and c or "_%02x" % ord(c) \
for c in value.encode('utf-8')])
def hex_encode(string):
return "".join([hex(ord(c))[2:].zfill(2) for c in string])
def alias_path(name):
return "/org/freedesktop/secrets/aliases/%s" % name
class PlainAlgorithm():
def negotiate(self, service, sender, param):
......@@ -178,23 +189,37 @@ class SecretSession(dbus.service.Object):
class SecretItem(dbus.service.Object):
def __init__(self, collection, identifier, label="Item", attributes={ },
secret="", confirm=False, content_type="text/plain",
schema="org.freedesktop.Secret.Generic"):
SUPPORTS_MULTIPLE_OBJECT_PATHS = True
def __init__(self, collection, identifier=None, label="Item", attributes={ },
secret="", confirm=False, content_type="text/plain", type=None):
if identifier is None:
identifier = next_identifier()
identifier = encode_identifier(identifier)
self.collection = collection
self.identifier = identifier
self.label = label or "Unnamed item"
self.secret = secret
self.schema = schema
self.type = type or "org.freedesktop.Secret.Generic"
self.attributes = attributes
self.content_type = content_type
self.path = "%s/%s" % (collection.path, identifier)
self.confirm = confirm
self.created = self.modified = time.time()
dbus.service.Object.__init__(self, collection.service.bus_name, self.path)
collection.items[identifier] = self
self.collection.add_item(self)
objects[self.path] = self
def add_alias(self, name):
path = "%s/%s" % (alias_path(name), self.identifier)
objects[path] = self
self.add_to_connection(self.connection, path)
def remove_alias(self, name):
path = "%s/%s" % (alias_path(name), self.identifier)
del objects[path]
self.remove_from_connection(self.connection, path)
def match_attributes(self, attributes):
for (key, value) in attributes.items():
if not self.attributes.get(key) == value:
......@@ -208,7 +233,7 @@ class SecretItem(dbus.service.Object):
return self.collection.perform_xlock(lock)
def perform_delete(self):
del self.collection.items[self.identifier]
self.collection.remove_item(self)
del objects[self.path]
self.remove_from_connection()
......@@ -216,7 +241,7 @@ class SecretItem(dbus.service.Object):
def GetSecret(self, session_path, sender=None):
session = objects.get(session_path, None)
if not session or session.sender != sender:
raise InvalidArgs("session invalid: %s" % session_path)
raise InvalidArgs("session invalid: %s" % session_path)
if self.get_locked():
raise IsLocked("secret is locked: %s" % self.path)
return session.encode_secret(self.secret, self.content_type)
......@@ -225,7 +250,7 @@ class SecretItem(dbus.service.Object):
def SetSecret(self, secret, sender=None):
session = objects.get(secret[0], None)
if not session or session.sender != sender:
raise InvalidArgs("session invalid: %s" % secret[0])
raise InvalidArgs("session invalid: %s" % secret[0])
if self.get_locked():
raise IsLocked("secret is locked: %s" % self.path)
(self.secret, self.content_type) = session.decode_secret(secret)
......@@ -257,7 +282,7 @@ class SecretItem(dbus.service.Object):
'Label': self.label,
'Created': dbus.UInt64(self.created),
'Modified': dbus.UInt64(self.modified),