示例#1
0
def search_items(connection: DBusConnection,
                 attributes: Dict[str, str]) -> Iterator[Item]:
	"""Returns a generator of items in all collections with the given
	attributes. `attributes` should be a dictionary."""
	service = DBusAddressWrapper(SS_PATH, SERVICE_IFACE, connection)
	locked, unlocked = service.call('SearchItems', 'a{ss}', attributes)
	for item_path in locked + unlocked:
		yield Item(connection, item_path)
示例#2
0
def search_items(connection: DBusConnection,
                 attributes: Dict[str, str]) -> Iterator[Item]:
    """Returns a generator of items in all collections with the given
	attributes. `attributes` should be a dictionary."""
    service = DBusAddressWrapper(SS_PATH, SERVICE_IFACE, connection)
    locked, unlocked = service.call('SearchItems', 'a{ss}', attributes)
    for item_path in locked + unlocked:
        yield Item(connection, item_path)
示例#3
0
 def __init__(self,
              connection: DBusConnection,
              item_path: str,
              session: Optional[Session] = None) -> None:
     self.item_path = item_path
     self._item = DBusAddressWrapper(item_path, ITEM_IFACE, connection)
     self._item.get_property('Label')
     self.session = session
     self.connection = connection
示例#4
0
 def __init__(self,
              connection: DBusConnection,
              collection_path: str = DEFAULT_COLLECTION,
              session: Optional[Session] = None) -> None:
     self.connection = connection
     self.session = session
     self.collection_path = collection_path
     self._collection = DBusAddressWrapper(collection_path,
                                           COLLECTION_IFACE, connection)
     self._collection.get_property('Label')
示例#5
0
def get_collection_by_alias(connection: DBusConnection,
                            alias: str) -> Collection:
    """Returns the collection with the given `alias`. If there is no
	such collection, raises
	:exc:`~secretstorage.exceptions.ItemNotFoundException`."""
    service = DBusAddressWrapper(SS_PATH, SERVICE_IFACE, connection)
    collection_path, = service.call('ReadAlias', 's', alias)
    if len(collection_path) <= 1:
        raise ItemNotFoundException('No collection with such alias.')
    return Collection(connection, collection_path)
示例#6
0
def get_collection_by_alias(connection: DBusConnection,
                            alias: str) -> Collection:
	"""Returns the collection with the given `alias`. If there is no
	such collection, raises
	:exc:`~secretstorage.exceptions.ItemNotFoundException`."""
	service = DBusAddressWrapper(SS_PATH, SERVICE_IFACE, connection)
	collection_path, = service.call('ReadAlias', 's', alias)
	if len(collection_path) <= 1:
		raise ItemNotFoundException('No collection with such alias.')
	return Collection(connection, collection_path)
示例#7
0
	def __init__(self, connection: DBusConnection,
	             collection_path: str = DEFAULT_COLLECTION,
	             session: Optional[Session] = None) -> None:
		self.connection = connection
		self.session = session
		self.collection_path = collection_path
		self._collection = DBusAddressWrapper(
			collection_path, COLLECTION_IFACE, connection)
		self._collection.get_property('Label')
示例#8
0
def create_collection(connection: DBusConnection, label: str, alias: str = '',
                      session: Optional[Session] = None) -> Collection:
	"""Creates a new :class:`Collection` with the given `label` and `alias`
	and returns it. This action requires prompting.

	:raises: :exc:`~secretstorage.exceptions.PromptDismissedException`
	         if the prompt is dismissed.
	"""
	if not session:
		session = open_session(connection)
	properties = {SS_PREFIX + 'Collection.Label': ('s', label)}
	service = DBusAddressWrapper(SS_PATH, SERVICE_IFACE, connection)
	collection_path, prompt = service.call('CreateCollection', 'a{sv}s',
	                                       properties, alias)
	if len(collection_path) > 1:
		return Collection(connection, collection_path, session=session)
	dismissed, result = exec_prompt(connection, prompt)
	if dismissed:
		raise PromptDismissedException('Prompt dismissed.')
	signature, collection_path = result
	assert signature == 'o'
	return Collection(connection, collection_path, session=session)
示例#9
0
def create_collection(connection: DBusConnection,
                      label: str,
                      alias: str = '',
                      session: Optional[Session] = None) -> Collection:
    """Creates a new :class:`Collection` with the given `label` and `alias`
	and returns it. This action requires prompting.

	:raises: :exc:`~secretstorage.exceptions.PromptDismissedException`
	         if the prompt is dismissed.
	"""
    if not session:
        session = open_session(connection)
    properties = {SS_PREFIX + 'Collection.Label': ('s', label)}
    service = DBusAddressWrapper(SS_PATH, SERVICE_IFACE, connection)
    collection_path, prompt = service.call('CreateCollection', 'a{sv}s',
                                           properties, alias)
    if len(collection_path) > 1:
        return Collection(connection, collection_path, session=session)
    dismissed, result = exec_prompt(connection, prompt)
    if dismissed:
        raise PromptDismissedException('Prompt dismissed.')
    signature, collection_path = result
    assert signature == 'o'
    return Collection(connection, collection_path, session=session)
示例#10
0
class Item(object):
    """Represents a secret item."""
    def __init__(self,
                 connection: DBusConnection,
                 item_path: str,
                 session: Optional[Session] = None) -> None:
        self.item_path = item_path
        self._item = DBusAddressWrapper(item_path, ITEM_IFACE, connection)
        self._item.get_property('Label')
        self.session = session
        self.connection = connection

    def __eq__(self, other: "DBusConnection") -> bool:
        assert isinstance(other.item_path, str)
        return self.item_path == other.item_path

    def is_locked(self) -> bool:
        """Returns :const:`True` if item is locked, otherwise
		:const:`False`."""
        return bool(self._item.get_property('Locked'))

    def ensure_not_locked(self) -> None:
        """If collection is locked, raises
		:exc:`~secretstorage.exceptions.LockedException`."""
        if self.is_locked():
            raise LockedException('Item is locked!')

    def unlock(self) -> bool:
        """Requests unlocking the item. Usually, this means that the
		whole collection containing this item will be unlocked.

		Returns a boolean representing whether the prompt has been
		dismissed; that means :const:`False` on successful unlocking
		and :const:`True` if it has been dismissed.

		.. versionadded:: 2.1.2

		.. versionchanged:: 3.0
		   No longer accepts the ``callback`` argument.
		"""
        return unlock_objects(self.connection, [self.item_path])

    def get_attributes(self) -> Dict[str, str]:
        """Returns item attributes (dictionary)."""
        attrs = self._item.get_property('Attributes')
        return dict(attrs)

    def set_attributes(self, attributes: Dict[str, str]) -> None:
        """Sets item attributes to `attributes` (dictionary)."""
        self._item.set_property('Attributes', 'a{ss}', attributes)

    def get_label(self) -> str:
        """Returns item label (unicode string)."""
        label = self._item.get_property('Label')
        assert isinstance(label, str)
        return label

    def set_label(self, label: str) -> None:
        """Sets item label to `label`."""
        self.ensure_not_locked()
        self._item.set_property('Label', 's', label)

    def delete(self) -> None:
        """Deletes the item."""
        self.ensure_not_locked()
        prompt, = self._item.call('Delete', '')
        if prompt != "/":
            dismissed, _result = exec_prompt(self.connection, prompt)
            if dismissed:
                raise PromptDismissedException('Prompt dismissed.')

    def get_secret(self) -> bytes:
        """Returns item secret (bytestring)."""
        self.ensure_not_locked()
        if not self.session:
            self.session = open_session(self.connection)
        secret, = self._item.call('GetSecret', 'o', self.session.object_path)
        if not self.session.encrypted:
            return bytes(secret[2])
        aes = algorithms.AES(self.session.aes_key)
        aes_iv = bytes(secret[1])
        decryptor = Cipher(aes, modes.CBC(aes_iv),
                           default_backend()).decryptor()
        encrypted_secret = secret[2]
        padded_secret = decryptor.update(
            encrypted_secret) + decryptor.finalize()
        assert isinstance(padded_secret, bytes)
        return padded_secret[:-padded_secret[-1]]

    def get_secret_content_type(self) -> str:
        """Returns content type of item secret (string)."""
        self.ensure_not_locked()
        if not self.session:
            self.session = open_session(self.connection)
        secret, = self._item.call('GetSecret', 'o', self.session.object_path)
        return str(secret[3])

    def set_secret(self,
                   secret: bytes,
                   content_type: str = 'text/plain') -> None:
        """Sets item secret to `secret`. If `content_type` is given,
		also sets the content type of the secret (``text/plain`` by
		default)."""
        self.ensure_not_locked()
        if not self.session:
            self.session = open_session(self.connection)
        _secret = format_secret(self.session, secret, content_type)
        self._item.call('SetSecret', '(oayays)', _secret)

    def get_created(self) -> int:
        """Returns UNIX timestamp (integer) representing the time
		when the item was created.

		.. versionadded:: 1.1"""
        created = self._item.get_property('Created')
        assert isinstance(created, int)
        return created

    def get_modified(self) -> int:
        """Returns UNIX timestamp (integer) representing the time
		when the item was last modified."""
        modified = self._item.get_property('Modified')
        assert isinstance(modified, int)
        return modified
示例#11
0
 def lock(self) -> None:
     """Locks the collection."""
     service = DBusAddressWrapper(SS_PATH, SERVICE_IFACE, self.connection)
     service.call('Lock', 'ao', [self.collection_path])
示例#12
0
class Collection(object):
    """Represents a collection."""
    def __init__(self,
                 connection: DBusConnection,
                 collection_path: str = DEFAULT_COLLECTION,
                 session: Optional[Session] = None) -> None:
        self.connection = connection
        self.session = session
        self.collection_path = collection_path
        self._collection = DBusAddressWrapper(collection_path,
                                              COLLECTION_IFACE, connection)
        self._collection.get_property('Label')

    def is_locked(self) -> bool:
        """Returns :const:`True` if item is locked, otherwise
		:const:`False`."""
        return bool(self._collection.get_property('Locked'))

    def ensure_not_locked(self) -> None:
        """If collection is locked, raises
		:exc:`~secretstorage.exceptions.LockedException`."""
        if self.is_locked():
            raise LockedException('Collection is locked!')

    def unlock(self) -> bool:
        """Requests unlocking the collection.

		Returns a boolean representing whether the prompt has been
		dismissed; that means :const:`False` on successful unlocking
		and :const:`True` if it has been dismissed.

		.. versionchanged:: 3.0
		   No longer accepts the ``callback`` argument.
		"""
        return unlock_objects(self.connection, [self.collection_path])

    def lock(self) -> None:
        """Locks the collection."""
        service = DBusAddressWrapper(SS_PATH, SERVICE_IFACE, self.connection)
        service.call('Lock', 'ao', [self.collection_path])

    def delete(self) -> None:
        """Deletes the collection and all items inside it."""
        self.ensure_not_locked()
        prompt, = self._collection.call('Delete', '')
        if prompt != "/":
            dismissed, _result = exec_prompt(self.connection, prompt)
            if dismissed:
                raise PromptDismissedException('Prompt dismissed.')

    def get_all_items(self) -> Iterator[Item]:
        """Returns a generator of all items in the collection."""
        for item_path in self._collection.get_property('Items'):
            yield Item(self.connection, item_path, self.session)

    def search_items(self, attributes: Dict[str, str]) -> Iterator[Item]:
        """Returns a generator of items with the given attributes.
		`attributes` should be a dictionary."""
        result, = self._collection.call('SearchItems', 'a{ss}', attributes)
        for item_path in result:
            yield Item(self.connection, item_path, self.session)

    def get_label(self) -> str:
        """Returns the collection label."""
        label = self._collection.get_property('Label')
        assert isinstance(label, str)
        return label

    def set_label(self, label: str) -> None:
        """Sets collection label to `label`."""
        self.ensure_not_locked()
        self._collection.set_property('Label', 's', label)

    def create_item(self,
                    label: str,
                    attributes: Dict[str, str],
                    secret: bytes,
                    replace: bool = False,
                    content_type: str = 'text/plain') -> Item:
        """Creates a new :class:`~secretstorage.item.Item` with given
		`label` (unicode string), `attributes` (dictionary) and `secret`
		(bytestring). If `replace` is :const:`True`, replaces the existing
		item with the same attributes. If `content_type` is given, also
		sets the content type of the secret (``text/plain`` by default).
		Returns the created item."""
        self.ensure_not_locked()
        if not self.session:
            self.session = open_session(self.connection)
        _secret = format_secret(self.session, secret, content_type)
        properties = {
            SS_PREFIX + 'Item.Label': ('s', label),
            SS_PREFIX + 'Item.Attributes': ('a{ss}', attributes),
        }
        new_item, prompt = self._collection.call('CreateItem',
                                                 'a{sv}(oayays)b', properties,
                                                 _secret, replace)
        return Item(self.connection, new_item, self.session)
示例#13
0
def get_all_collections(connection: DBusConnection) -> Iterator[Collection]:
    """Returns a generator of all available collections."""
    service = DBusAddressWrapper(SS_PATH, SERVICE_IFACE, connection)
    for collection_path in service.get_property('Collections'):
        yield Collection(connection, collection_path)
示例#14
0
	def lock(self) -> None:
		"""Locks the collection."""
		service = DBusAddressWrapper(SS_PATH, SERVICE_IFACE, self.connection)
		service.call('Lock', 'ao', [self.collection_path])
示例#15
0
class Collection(object):
	"""Represents a collection."""

	def __init__(self, connection: DBusConnection,
	             collection_path: str = DEFAULT_COLLECTION,
	             session: Optional[Session] = None) -> None:
		self.connection = connection
		self.session = session
		self.collection_path = collection_path
		self._collection = DBusAddressWrapper(
			collection_path, COLLECTION_IFACE, connection)
		self._collection.get_property('Label')

	def is_locked(self) -> bool:
		"""Returns :const:`True` if item is locked, otherwise
		:const:`False`."""
		return bool(self._collection.get_property('Locked'))

	def ensure_not_locked(self) -> None:
		"""If collection is locked, raises
		:exc:`~secretstorage.exceptions.LockedException`."""
		if self.is_locked():
			raise LockedException('Collection is locked!')

	def unlock(self) -> bool:
		"""Requests unlocking the collection.

		Returns a boolean representing whether the prompt has been
		dismissed; that means :const:`False` on successful unlocking
		and :const:`True` if it has been dismissed.

		.. versionchanged:: 3.0
		   No longer accepts the ``callback`` argument.
		"""
		return unlock_objects(self.connection, [self.collection_path])

	def lock(self) -> None:
		"""Locks the collection."""
		service = DBusAddressWrapper(SS_PATH, SERVICE_IFACE, self.connection)
		service.call('Lock', 'ao', [self.collection_path])

	def delete(self) -> None:
		"""Deletes the collection and all items inside it."""
		self.ensure_not_locked()
		prompt, = self._collection.call('Delete', '')
		if prompt != "/":
			dismissed, _result = exec_prompt(self.connection, prompt)
			if dismissed:
				raise PromptDismissedException('Prompt dismissed.')

	def get_all_items(self) -> Iterator[Item]:
		"""Returns a generator of all items in the collection."""
		for item_path in self._collection.get_property('Items'):
			yield Item(self.connection, item_path, self.session)

	def search_items(self, attributes: Dict[str, str]) -> Iterator[Item]:
		"""Returns a generator of items with the given attributes.
		`attributes` should be a dictionary."""
		result, = self._collection.call('SearchItems', 'a{ss}', attributes)
		for item_path in result:
			yield Item(self.connection, item_path, self.session)

	def get_label(self) -> str:
		"""Returns the collection label."""
		label = self._collection.get_property('Label')
		assert isinstance(label, str)
		return label

	def set_label(self, label: str) -> None:
		"""Sets collection label to `label`."""
		self.ensure_not_locked()
		self._collection.set_property('Label', 's', label)

	def create_item(self, label: str, attributes: Dict[str, str],
	                secret: bytes, replace: bool = False,
	                content_type: str = 'text/plain') -> Item:
		"""Creates a new :class:`~secretstorage.item.Item` with given
		`label` (unicode string), `attributes` (dictionary) and `secret`
		(bytestring). If `replace` is :const:`True`, replaces the existing
		item with the same attributes. If `content_type` is given, also
		sets the content type of the secret (``text/plain`` by default).
		Returns the created item."""
		self.ensure_not_locked()
		if not self.session:
			self.session = open_session(self.connection)
		_secret = format_secret(self.session, secret, content_type)
		properties = {
			SS_PREFIX + 'Item.Label': ('s', label),
			SS_PREFIX + 'Item.Attributes': ('a{ss}', attributes),
		}
		new_item, prompt = self._collection.call('CreateItem', 'a{sv}(oayays)b',
		                                         properties, _secret, replace)
		return Item(self.connection, new_item, self.session)
示例#16
0
def get_all_collections(connection: DBusConnection) -> Iterator[Collection]:
	"""Returns a generator of all available collections."""
	service = DBusAddressWrapper(SS_PATH, SERVICE_IFACE, connection)
	for collection_path in service.get_property('Collections'):
		yield Collection(connection, collection_path)