Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
libsecret.py135 linesDownload Raw Back to msal_extensions
1"""Implements a Linux specific TokenCache, and provides auxiliary helper types.2 3This module depends on PyGObject. But `pip install pygobject` would typically fail,4until you install its dependencies first. For example, on a Debian Linux, you need::5 6    sudo apt install libgirepository1.0-dev libcairo2-dev python3-dev gir1.2-secret-17    pip install pygobject8 9Alternatively, you could skip Cairo & PyCairo, but you still need to do all these10(derived from https://gitlab.gnome.org/GNOME/pygobject/-/issues/395)::11 12    sudo apt install libgirepository1.0-dev python3-dev gir1.2-secret-113    pip install wheel14    PYGOBJECT_WITHOUT_PYCAIRO=1 pip install --no-build-isolation pygobject15"""16 17try:18    import gi  # https://github.com/AzureAD/microsoft-authentication-extensions-for-python/wiki/Encryption-on-Linux  # pylint: disable=line-too-long19except ImportError:20    raise ImportError("""Unable to import module 'gi'21Runtime dependency of PyGObject is missing.22Depends on your Linux distro, you could install it system-wide by something like:23    sudo apt install python3-gi python3-gi-cairo gir1.2-secret-124If necessary, please refer to PyGObject's doc:25https://pygobject.readthedocs.io/en/latest/getting_started.html26""")  # Message via exception rather than log27 28try:29    # pylint: disable=no-name-in-module30    gi.require_version("Secret", "1")  # Would require a package gir1.2-secret-131    # pylint: disable=wrong-import-position32    from gi.repository import Secret  # Would require a package gir1.2-secret-133except (ValueError, ImportError) as ex:34    raise type(ex)(35        """Require a package "gir1.2-secret-1" which could be installed by:36        sudo apt install gir1.2-secret-137        """)  # Message via exception rather than log38 39 40class LibSecretAgent(object):41    """A loader/saver built on top of low-level libsecret"""42    # Inspired by https://developer.gnome.org/libsecret/unstable/py-examples.html43    def __init__(  # pylint: disable=too-many-arguments44            self,45            schema_name,46            attributes,  # {"name": "value", ...}47            label="",  # Helpful when visualizing secrets by other viewers48            attribute_types=None,  # {name: SchemaAttributeType, ...}49            collection=None,  # None means default collection50            ):51        """This agent is built on top of lower level libsecret API.52 53        Content stored via libsecret is associated with a bunch of attributes.54 55        :param string schema_name:56            Attributes would conceptually follow an existing schema.57            But this class will do it in the other way around,58            by automatically deriving a schema based on your attributes.59            However, you will still need to provide a schema_name.60            load() and save() will only operate on data with matching schema_name.61 62        :param dict attributes:63            Attributes are key-value pairs, represented as a Python dict here.64            They will be used to filter content during load() and save().65            Their arbitrary keys are strings.66            Their arbitrary values can MEAN strings, integers and booleans,67            but are always represented as strings, according to upstream sample:68            https://developer.gnome.org/libsecret/0.18/py-store-example.html69 70        :param string label:71            It will not be used during data lookup and filtering.72            It is only helpful when/if you visualize secrets by other viewers.73 74        :param dict attribute_types:75            Each key is the name of your each attribute.76            The corresponding value will be one of the following three:77 78            * Secret.SchemaAttributeType.STRING79            * Secret.SchemaAttributeType.INTEGER80            * Secret.SchemaAttributeType.BOOLEAN81 82            But if all your attributes are Secret.SchemaAttributeType.STRING,83            you do not need to provide this types definition at all.84 85        :param collection:86            The default value `None` means default collection.87        """88        self._collection = collection89        self._attributes = attributes or {}90        self._label = label91        self._schema = Secret.Schema.new(schema_name, Secret.SchemaFlags.NONE, {92            k: (attribute_types or {}).get(k, Secret.SchemaAttributeType.STRING)93            for k in self._attributes})94 95    def save(self, data):96        """Store data. Returns a boolean of whether operation was successful."""97        return Secret.password_store_sync(98            self._schema, self._attributes, self._collection, self._label,99            data, None)100 101    def load(self):102        """Load a password in the secret service, return None when found nothing"""103        return Secret.password_lookup_sync(self._schema, self._attributes, None)104 105    def clear(self):106        """Returns a boolean of whether any passwords were removed"""107        return Secret.password_clear_sync(self._schema, self._attributes, None)108 109 110def trial_run():111    """This trial run will raise an exception if libsecret is not functioning.112 113    Even after you installed all the dependencies so that your script can start,114    or even if your previous run was successful, your script could fail next time,115    for example when it will be running inside a headless SSH session.116 117    You do not have to do trial_run. The exception would also be raised by save().118    """119    try:120        agent = LibSecretAgent("Test Schema", {"attr1": "foo", "attr2": "bar"})121        payload = "Test Data"122        agent.save(payload)  # It would fail when running inside an SSH session123        assert agent.load() == payload  # This line is probably not reachable124        agent.clear()125    except (gi.repository.GLib.Error, AssertionError):  # pylint: disable=no-member126        # https://pygobject.readthedocs.io/en/latest/guide/api/error_handling.html#examples127        message = """libsecret did not perform properly.128* If you encountered error "Remote error from secret service:129  org.freedesktop.DBus.Error.ServiceUnknown",130  you may need to install gnome-keyring package.131* Headless mode (such as in an ssh session) is not supported.132"""133        raise RuntimeError(message)  # Message via exception rather than log134 135