From cf2dc1f70e5507f466998e610e0faf76f5882916 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 11:31:04 +0200 Subject: [PATCH 01/14] renamed PypeSettingsRegistry to OpenPypeSettingsRegistry --- openpype/lib/__init__.py | 4 ++-- openpype/lib/local_settings.py | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index 554c0d8ec3..7b2f533921 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -104,7 +104,7 @@ from .plugin_tools import ( from .local_settings import ( IniSettingRegistry, JSONSettingRegistry, - PypeSettingsRegistry, + OpenPypeSettingsRegistry, get_local_site_id, change_openpype_mongo_url ) @@ -217,7 +217,7 @@ __all__ = [ "IniSettingRegistry", "JSONSettingRegistry", - "PypeSettingsRegistry", + "OpenPypeSettingsRegistry", "get_local_site_id", "change_openpype_mongo_url", diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index 82507cb0c0..2095f1253e 100644 --- a/openpype/lib/local_settings.py +++ b/openpype/lib/local_settings.py @@ -452,7 +452,7 @@ class JSONSettingRegistry(ASettingRegistry): json.dump(data, cfg, indent=4) -class PypeSettingsRegistry(JSONSettingRegistry): +class OpenPypeSettingsRegistry(JSONSettingRegistry): """Class handling Pype general settings registry. Attributes: @@ -463,9 +463,9 @@ class PypeSettingsRegistry(JSONSettingRegistry): def __init__(self): self.vendor = "pypeclub" - self.product = "pype" + self.product = "openpype" path = appdirs.user_data_dir(self.product, self.vendor) - super(PypeSettingsRegistry, self).__init__("pype_settings", path) + super(OpenPypeSettingsRegistry, self).__init__("openpype_settings", path) def _create_local_site_id(registry=None): @@ -473,7 +473,7 @@ def _create_local_site_id(registry=None): from uuid import uuid4 if registry is None: - registry = PypeSettingsRegistry() + registry = OpenPypeSettingsRegistry() new_id = str(uuid4()) @@ -489,7 +489,7 @@ def get_local_site_id(): Identifier is created if does not exists yet. """ - registry = PypeSettingsRegistry() + registry = OpenPypeSettingsRegistry() try: return registry.get_item("localId") except ValueError: @@ -504,5 +504,5 @@ def change_openpype_mongo_url(new_mongo_url): """ validate_mongo_connection(new_mongo_url) - registry = PypeSettingsRegistry() - registry.set_secure_item("pypeMongo", new_mongo_url) + registry = OpenPypeSettingsRegistry() + registry.set_secure_item("openPypeMongo", new_mongo_url) From a6ac99c7558273f093a7c41a95fc68b37778beeb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 11:31:41 +0200 Subject: [PATCH 02/14] added ability to define name of registry --- igniter/user_settings.py | 7 ++++--- openpype/lib/local_settings.py | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/igniter/user_settings.py b/igniter/user_settings.py index 77fb8b5ae5..f9bbad4e5e 100644 --- a/igniter/user_settings.py +++ b/igniter/user_settings.py @@ -459,9 +459,10 @@ class OpenPypeSettingsRegistry(JSONSettingRegistry): """ - def __init__(self): + def __init__(self, name=None): self.vendor = "pypeclub" self.product = "openpype" + if name is None: + name = "openpype_settings" path = appdirs.user_data_dir(self.product, self.vendor) - super(OpenPypeSettingsRegistry, self).__init__( - "openpype_settings", path) + super(OpenPypeSettingsRegistry, self).__init__(name, path) diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index 2095f1253e..6386a69026 100644 --- a/openpype/lib/local_settings.py +++ b/openpype/lib/local_settings.py @@ -461,11 +461,13 @@ class OpenPypeSettingsRegistry(JSONSettingRegistry): """ - def __init__(self): + def __init__(self, name=None): self.vendor = "pypeclub" self.product = "openpype" + if name is None: + name = "openpype_settings" path = appdirs.user_data_dir(self.product, self.vendor) - super(OpenPypeSettingsRegistry, self).__init__("openpype_settings", path) + super(OpenPypeSettingsRegistry, self).__init__(name, path) def _create_local_site_id(registry=None): From 11fe828809c7399f2aeba8a97a68736db2b41ae5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 11:52:59 +0200 Subject: [PATCH 03/14] fix tests --- tests/igniter/test_bootstrap_repos.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/igniter/test_bootstrap_repos.py b/tests/igniter/test_bootstrap_repos.py index 75996b4026..6c70380ab6 100644 --- a/tests/igniter/test_bootstrap_repos.py +++ b/tests/igniter/test_bootstrap_repos.py @@ -11,7 +11,7 @@ import pytest from igniter.bootstrap_repos import BootstrapRepos from igniter.bootstrap_repos import PypeVersion -from pype.lib import PypeSettingsRegistry +from pype.lib import OpenPypeSettingsRegistry @pytest.fixture @@ -348,7 +348,7 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): return d_path.as_posix() monkeypatch.setattr(appdirs, "user_data_dir", mock_user_data_dir) - fix_bootstrap.registry = PypeSettingsRegistry() + fix_bootstrap.registry = OpenPypeSettingsRegistry() fix_bootstrap.registry.set_item("pypePath", d_path.as_posix()) result = fix_bootstrap.find_pype(include_zips=True) From 68fe4c8a934ffac8df4307d2cbd3768bb3feb6ae Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 15:32:32 +0200 Subject: [PATCH 04/14] implemented OpenPypeSecureRegistry handling keyring information --- igniter/user_settings.py | 93 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/igniter/user_settings.py b/igniter/user_settings.py index f9bbad4e5e..1d4fcd04eb 100644 --- a/igniter/user_settings.py +++ b/igniter/user_settings.py @@ -28,6 +28,99 @@ import platform import appdirs import six +_PLACEHOLDER = object() + + +class OpenPypeSecureRegistry: + def __init__(self, name): + try: + import keyring + + except Exception: + raise NotImplementedError( + "Python module `keyring` is not available." + ) + + # hack for cx_freeze and Windows keyring backend + if platform.system().lower() == "windows": + from keyring.backends import Windows + + keyring.set_keyring(Windows.WinVaultKeyring()) + + # Force "OpenPype" prefix + self._name = "/".join(("OpenPype", name)) + + def set_item(self, name, value): + # type: (str, str) -> None + """Set sensitive item into system's keyring. + + This uses `Keyring module`_ to save sensitive stuff into system's + keyring. + + Args: + name (str): Name of the item. + value (str): Value of the item. + + .. _Keyring module: + https://github.com/jaraco/keyring + + """ + import keyring + + keyring.set_password(self._name, name, value) + + @lru_cache(maxsize=32) + def get_item(self, name, default=_PLACEHOLDER): + """Get value of sensitive item from system's keyring. + + See also `Keyring module`_ + + Args: + name (str): Name of the item. + default (Any): Default value if item is not available. + + Returns: + value (str): Value of the item. + + Raises: + ValueError: If item doesn't exist and default is not defined. + + .. _Keyring module: + https://github.com/jaraco/keyring + + """ + import keyring + + value = keyring.get_password(self._name, name) + if value: + return value + + if default is not _PLACEHOLDER: + return default + + # NOTE Should raise `KeyError` + raise ValueError( + "Item {}:{} does not exist in keyring.".format(self._name, name) + ) + + def delete_item(self, name): + # type: (str) -> None + """Delete value stored in system's keyring. + + See also `Keyring module`_ + + Args: + name (str): Name of the item to be deleted. + + .. _Keyring module: + https://github.com/jaraco/keyring + + """ + import keyring + + self.get_item.cache_clear() + keyring.delete_password(self._name, name) + @six.add_metaclass(ABCMeta) class ASettingRegistry(): From d08fde832a2b4c7d5fccee8772c3646cbc3be47a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 15:34:30 +0200 Subject: [PATCH 05/14] bootstrap repos also has secure_registry which is used for mongo url storage --- igniter/bootstrap_repos.py | 6 +++++- igniter/install_thread.py | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 2f305e24e3..51dec7f51e 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -14,7 +14,10 @@ from zipfile import ZipFile, BadZipFile from appdirs import user_data_dir from speedcopy import copyfile -from .user_settings import OpenPypeSettingsRegistry +from .user_settings import ( + OpenPypeSecureRegistry, + OpenPypeSettingsRegistry +) from .tools import get_openpype_path_from_db @@ -239,6 +242,7 @@ class BootstrapRepos: self._app = "openpype" self._log = log.getLogger(str(__class__)) self.data_dir = Path(user_data_dir(self._app, self._vendor)) + self.secure_registry = OpenPypeSecureRegistry("Settings") self.registry = OpenPypeSettingsRegistry() self.zip_filter = [".pyc", "__pycache__"] self.openpype_filter = [ diff --git a/igniter/install_thread.py b/igniter/install_thread.py index bf5d541056..df8b830209 100644 --- a/igniter/install_thread.py +++ b/igniter/install_thread.py @@ -71,7 +71,7 @@ class InstallThread(QThread): if not os.getenv("OPENPYPE_MONGO"): # try to get it from settings registry try: - self._mongo = bs.registry.get_secure_item( + self._mongo = bs.secure_registry.get_item( "openPypeMongo") except ValueError: self.message.emit( @@ -82,7 +82,7 @@ class InstallThread(QThread): self._mongo = os.getenv("OPENPYPE_MONGO") else: self.message.emit("Saving mongo connection string ...", False) - bs.registry.set_secure_item("openPypeMongo", self._mongo) + bs.secure_registry.set_item("openPypeMongo", self._mongo) os.environ["OPENPYPE_MONGO"] = self._mongo @@ -169,7 +169,7 @@ class InstallThread(QThread): f"!!! invalid mongo url {self._mongo}", True) self.finished.emit(InstallResult(-1)) return - bs.registry.set_secure_item("openPypeMongo", self._mongo) + bs.secure_registry.set_item("openPypeMongo", self._mongo) os.environ["OPENPYPE_MONGO"] = self._mongo self.message.emit(f"processing {self._path}", True) From 41beb27a693e7d808da72595c83c7ca003d98309 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 15:35:15 +0200 Subject: [PATCH 06/14] secure registry is also used in install dialog --- igniter/install_dialog.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/igniter/install_dialog.py b/igniter/install_dialog.py index 2cc0ed8448..dab00079a5 100644 --- a/igniter/install_dialog.py +++ b/igniter/install_dialog.py @@ -13,7 +13,7 @@ from .tools import ( validate_mongo_connection, get_openpype_path_from_db ) -from .user_settings import OpenPypeSettingsRegistry +from .user_settings import OpenPypeSecureRegistry from .version import __version__ @@ -42,13 +42,13 @@ class InstallDialog(QtWidgets.QDialog): def __init__(self, parent=None): super(InstallDialog, self).__init__(parent) - self.registry = OpenPypeSettingsRegistry() + self.secure_registry = OpenPypeSecureRegistry("Settings") self.mongo_url = "" try: self.mongo_url = ( os.getenv("OPENPYPE_MONGO", "") - or self.registry.get_secure_item("openPypeMongo") + or self.secure_registry.get_item("openPypeMongo") ) except ValueError: pass From 3cc8599684a7374c98a9cd375fce588e382d91aa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 15:36:22 +0200 Subject: [PATCH 07/14] removed secure getter and setters from ASettingRegistry --- igniter/user_settings.py | 83 +--------------------------------------- 1 file changed, 2 insertions(+), 81 deletions(-) diff --git a/igniter/user_settings.py b/igniter/user_settings.py index 1d4fcd04eb..bb5336a9ab 100644 --- a/igniter/user_settings.py +++ b/igniter/user_settings.py @@ -25,8 +25,8 @@ except ImportError: import platform -import appdirs import six +import appdirs _PLACEHOLDER = object() @@ -139,13 +139,6 @@ class ASettingRegistry(): # type: (str) -> ASettingRegistry super(ASettingRegistry, self).__init__() - if six.PY3: - import keyring - # hack for cx_freeze and Windows keyring backend - if platform.system() == "Windows": - from keyring.backends import Windows - keyring.set_keyring(Windows.WinVaultKeyring()) - self._name = name self._items = {} @@ -220,78 +213,6 @@ class ASettingRegistry(): del self._items[name] self._delete_item(name) - def set_secure_item(self, name, value): - # type: (str, str) -> None - """Set sensitive item into system's keyring. - - This uses `Keyring module`_ to save sensitive stuff into system's - keyring. - - Args: - name (str): Name of the item. - value (str): Value of the item. - - .. _Keyring module: - https://github.com/jaraco/keyring - - """ - if six.PY2: - raise NotImplementedError( - "Keyring not available on Python 2 hosts") - import keyring - keyring.set_password(self._name, name, value) - - @lru_cache(maxsize=32) - def get_secure_item(self, name): - # type: (str) -> str - """Get value of sensitive item from system's keyring. - - See also `Keyring module`_ - - Args: - name (str): Name of the item. - - Returns: - value (str): Value of the item. - - Raises: - ValueError: If item doesn't exist. - - .. _Keyring module: - https://github.com/jaraco/keyring - - """ - if six.PY2: - raise NotImplementedError( - "Keyring not available on Python 2 hosts") - import keyring - value = keyring.get_password(self._name, name) - if not value: - raise ValueError( - "Item {}:{} does not exist in keyring.".format( - self._name, name)) - return value - - def delete_secure_item(self, name): - # type: (str) -> None - """Delete value stored in system's keyring. - - See also `Keyring module`_ - - Args: - name (str): Name of the item to be deleted. - - .. _Keyring module: - https://github.com/jaraco/keyring - - """ - if six.PY2: - raise NotImplementedError( - "Keyring not available on Python 2 hosts") - import keyring - self.get_secure_item.cache_clear() - keyring.delete_password(self._name, name) - class IniSettingRegistry(ASettingRegistry): """Class using :mod:`configparser`. @@ -555,7 +476,7 @@ class OpenPypeSettingsRegistry(JSONSettingRegistry): def __init__(self, name=None): self.vendor = "pypeclub" self.product = "openpype" - if name is None: + if not name: name = "openpype_settings" path = appdirs.user_data_dir(self.product, self.vendor) super(OpenPypeSettingsRegistry, self).__init__(name, path) From 454bd9d1b51b4b4782bff4e2afbaba2d7102aad4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 15:40:21 +0200 Subject: [PATCH 08/14] copy pasted secure registry logic from igniter to pype lib --- openpype/lib/local_settings.py | 195 ++++++++++++++++++--------------- 1 file changed, 105 insertions(+), 90 deletions(-) diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index 6386a69026..ec76b57cfd 100644 --- a/openpype/lib/local_settings.py +++ b/openpype/lib/local_settings.py @@ -5,6 +5,7 @@ from datetime import datetime from abc import ABCMeta, abstractmethod import json +# TODO Use pype igniter logic instead of using duplicated code # disable lru cache in Python 2 try: from functools import lru_cache @@ -25,11 +26,104 @@ except ImportError: import platform -import appdirs import six +import appdirs from .import validate_mongo_connection +_PLACEHOLDER = object() + + +class OpenPypeSecureRegistry: + def __init__(self, name): + try: + import keyring + + except Exception: + raise NotImplementedError( + "Python module `keyring` is not available." + ) + + # hack for cx_freeze and Windows keyring backend + if platform.system().lower() == "windows": + from keyring.backends import Windows + + keyring.set_keyring(Windows.WinVaultKeyring()) + + # Force "OpenPype" prefix + self._name = "/".join(("OpenPype", name)) + + def set_item(self, name, value): + # type: (str, str) -> None + """Set sensitive item into system's keyring. + + This uses `Keyring module`_ to save sensitive stuff into system's + keyring. + + Args: + name (str): Name of the item. + value (str): Value of the item. + + .. _Keyring module: + https://github.com/jaraco/keyring + + """ + import keyring + + keyring.set_password(self._name, name, value) + + @lru_cache(maxsize=32) + def get_item(self, name, default=_PLACEHOLDER): + """Get value of sensitive item from system's keyring. + + See also `Keyring module`_ + + Args: + name (str): Name of the item. + default (Any): Default value if item is not available. + + Returns: + value (str): Value of the item. + + Raises: + ValueError: If item doesn't exist and default is not defined. + + .. _Keyring module: + https://github.com/jaraco/keyring + + """ + import keyring + + value = keyring.get_password(self._name, name) + if value: + return value + + if default is not _PLACEHOLDER: + return default + + # NOTE Should raise `KeyError` + raise ValueError( + "Item {}:{} does not exist in keyring.".format(self._name, name) + ) + + def delete_item(self, name): + # type: (str) -> None + """Delete value stored in system's keyring. + + See also `Keyring module`_ + + Args: + name (str): Name of the item to be deleted. + + .. _Keyring module: + https://github.com/jaraco/keyring + + """ + import keyring + + self.get_item.cache_clear() + keyring.delete_password(self._name, name) + @six.add_metaclass(ABCMeta) class ASettingRegistry(): @@ -48,13 +142,6 @@ class ASettingRegistry(): # type: (str) -> ASettingRegistry super(ASettingRegistry, self).__init__() - if six.PY3: - import keyring - # hack for cx_freeze and Windows keyring backend - if platform.system() == "Windows": - from keyring.backends import Windows - keyring.set_keyring(Windows.WinVaultKeyring()) - self._name = name self._items = {} @@ -120,7 +207,7 @@ class ASettingRegistry(): """Delete item from settings. Note: - see :meth:`pype.lib.local_settings.ARegistrySettings.delete_item` + see :meth:`openpype.lib.user_settings.ARegistrySettings.delete_item` """ pass @@ -129,78 +216,6 @@ class ASettingRegistry(): del self._items[name] self._delete_item(name) - def set_secure_item(self, name, value): - # type: (str, str) -> None - """Set sensitive item into system's keyring. - - This uses `Keyring module`_ to save sensitive stuff into system's - keyring. - - Args: - name (str): Name of the item. - value (str): Value of the item. - - .. _Keyring module: - https://github.com/jaraco/keyring - - """ - if six.PY2: - raise NotImplementedError( - "Keyring not available on Python 2 hosts") - import keyring - keyring.set_password(self._name, name, value) - - @lru_cache(maxsize=32) - def get_secure_item(self, name): - # type: (str) -> str - """Get value of sensitive item from system's keyring. - - See also `Keyring module`_ - - Args: - name (str): Name of the item. - - Returns: - value (str): Value of the item. - - Raises: - ValueError: If item doesn't exist. - - .. _Keyring module: - https://github.com/jaraco/keyring - - """ - if six.PY2: - raise NotImplementedError( - "Keyring not available on Python 2 hosts") - import keyring - value = keyring.get_password(self._name, name) - if not value: - raise ValueError( - "Item {}:{} does not exist in keyring.".format( - self._name, name)) - return value - - def delete_secure_item(self, name): - # type: (str) -> None - """Delete value stored in system's keyring. - - See also `Keyring module`_ - - Args: - name (str): Name of the item to be deleted. - - .. _Keyring module: - https://github.com/jaraco/keyring - - """ - if six.PY2: - raise NotImplementedError( - "Keyring not available on Python 2 hosts") - import keyring - self.get_secure_item.cache_clear() - keyring.delete_password(self._name, name) - class IniSettingRegistry(ASettingRegistry): """Class using :mod:`configparser`. @@ -218,7 +233,7 @@ class IniSettingRegistry(ASettingRegistry): if not os.path.exists(self._registry_file): with open(self._registry_file, mode="w") as cfg: print("# Settings registry", cfg) - print("# Generated by Pype {}".format(version), cfg) + print("# Generated by OpenPype {}".format(version), cfg) now = datetime.now().strftime("%d/%m/%Y %H:%M:%S") print("# {}".format(now), cfg) @@ -352,7 +367,7 @@ class IniSettingRegistry(ASettingRegistry): """Delete item from default section. Note: - See :meth:`~pype.lib.IniSettingsRegistry.delete_item_from_section` + See :meth:`~openpype.lib.IniSettingsRegistry.delete_item_from_section` """ self.delete_item_from_section("MAIN", name) @@ -369,7 +384,7 @@ class JSONSettingRegistry(ASettingRegistry): now = datetime.now().strftime("%d/%m/%Y %H:%M:%S") header = { "__metadata__": { - "pype-version": os.getenv("OPENPYPE_VERSION", "N/A"), + "openpype-version": os.getenv("OPENPYPE_VERSION", "N/A"), "generated": now }, "registry": {} @@ -387,7 +402,7 @@ class JSONSettingRegistry(ASettingRegistry): """Get item value from registry json. Note: - See :meth:`pype.lib.JSONSettingRegistry.get_item` + See :meth:`openpype.lib.JSONSettingRegistry.get_item` """ with open(self._registry_file, mode="r") as cfg: @@ -420,7 +435,7 @@ class JSONSettingRegistry(ASettingRegistry): """Set item value to registry json. Note: - See :meth:`pype.lib.JSONSettingRegistry.set_item` + See :meth:`openpype.lib.JSONSettingRegistry.set_item` """ with open(self._registry_file, "r+") as cfg: @@ -453,7 +468,7 @@ class JSONSettingRegistry(ASettingRegistry): class OpenPypeSettingsRegistry(JSONSettingRegistry): - """Class handling Pype general settings registry. + """Class handling OpenPype general settings registry. Attributes: vendor (str): Name used for path construction. @@ -464,7 +479,7 @@ class OpenPypeSettingsRegistry(JSONSettingRegistry): def __init__(self, name=None): self.vendor = "pypeclub" self.product = "openpype" - if name is None: + if not name: name = "openpype_settings" path = appdirs.user_data_dir(self.product, self.vendor) super(OpenPypeSettingsRegistry, self).__init__(name, path) @@ -506,5 +521,5 @@ def change_openpype_mongo_url(new_mongo_url): """ validate_mongo_connection(new_mongo_url) - registry = OpenPypeSettingsRegistry() - registry.set_secure_item("openPypeMongo", new_mongo_url) + registry = OpenPypeSecureRegistry("Settings") + registry.set_item("openPypeMongo", new_mongo_url) From 3785e9b53c5fc90bcfb32ea6dc39afb965b9e130 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 16:54:03 +0200 Subject: [PATCH 09/14] fix tests --- tests/pype/lib/test_user_settings.py | 32 ++++++++++++++++++---------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/tests/pype/lib/test_user_settings.py b/tests/pype/lib/test_user_settings.py index 7f0f400f59..02342abbc9 100644 --- a/tests/pype/lib/test_user_settings.py +++ b/tests/pype/lib/test_user_settings.py @@ -1,10 +1,20 @@ import pytest -from pype.lib import IniSettingRegistry -from pype.lib import JSONSettingRegistry +from pype.lib import ( + IniSettingRegistry, + JSONSettingRegistry, + OpenPypeSecureRegistry +) from uuid import uuid4 import configparser +@pytest.fixture +def secure_registry(tmpdir): + name = "pypetest_{}".format(str(uuid4())) + r = OpenPypeSecureRegistry(name, tmpdir) + yield r + + @pytest.fixture def json_registry(tmpdir): name = "pypetest_{}".format(str(uuid4())) @@ -19,21 +29,21 @@ def ini_registry(tmpdir): yield r -def test_keyring(json_registry): - json_registry.set_secure_item("item1", "foo") - json_registry.set_secure_item("item2", "bar") - result1 = json_registry.get_secure_item("item1") - result2 = json_registry.get_secure_item("item2") +def test_keyring(secure_registry): + secure_registry.set_item("item1", "foo") + secure_registry.set_item("item2", "bar") + result1 = secure_registry.get_item("item1") + result2 = secure_registry.get_item("item2") assert result1 == "foo" assert result2 == "bar" - json_registry.delete_secure_item("item1") - json_registry.delete_secure_item("item2") + secure_registry.delete_item("item1") + secure_registry.delete_item("item2") with pytest.raises(ValueError): - json_registry.get_secure_item("item1") - json_registry.get_secure_item("item2") + secure_registry.get_item("item1") + secure_registry.get_item("item2") def test_ini_registry(ini_registry): From ee93c229fef4ed0b3cde55b6384bd8b704b7deac Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 16:54:32 +0200 Subject: [PATCH 10/14] added some docstring to OpenPypeSecureRegistry --- igniter/user_settings.py | 11 +++++++++++ openpype/lib/local_settings.py | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/igniter/user_settings.py b/igniter/user_settings.py index bb5336a9ab..2a406f83dd 100644 --- a/igniter/user_settings.py +++ b/igniter/user_settings.py @@ -32,6 +32,17 @@ _PLACEHOLDER = object() class OpenPypeSecureRegistry: + """Store information using keyring. + + Registry should be used for private data that should be available only for + user. + + All passed registry names will have added prefix `OpenPype/` to easier + identify which data were created by OpenPype. + + Args: + name(str): Name of registry used as identifier for data. + """ def __init__(self, name): try: import keyring diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index ec76b57cfd..1bd8540acb 100644 --- a/openpype/lib/local_settings.py +++ b/openpype/lib/local_settings.py @@ -35,6 +35,17 @@ _PLACEHOLDER = object() class OpenPypeSecureRegistry: + """Store information using keyring. + + Registry should be used for private data that should be available only for + user. + + All passed registry names will have added prefix `OpenPype/` to easier + identify which data were created by OpenPype. + + Args: + name(str): Name of registry used as identifier for data. + """ def __init__(self, name): try: import keyring From e81c9dd5b5ad7020d1da8ebfe39ab86854e2aafb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 16:54:55 +0200 Subject: [PATCH 11/14] fix bootstrap attribute access --- start.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start.py b/start.py index 1f946a705c..36e4c36d21 100644 --- a/start.py +++ b/start.py @@ -296,7 +296,7 @@ def _determine_mongodb() -> str: if not openpype_mongo: # try system keyring try: - openpype_mongo = bootstrap.registry.get_secure_item( + openpype_mongo = bootstrap.secure_registry.get_item( "openPypeMongo") except ValueError: print("*** No DB connection string specified.") @@ -305,7 +305,7 @@ def _determine_mongodb() -> str: igniter.open_dialog() try: - openpype_mongo = bootstrap.registry.get_secure_item( + openpype_mongo = bootstrap.secure_registry.get_item( "openPypeMongo") except ValueError: raise RuntimeError("missing mongodb url") From 787d037ca02a1a7e295a446bd459b7c7b6ec8e5b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 17:08:04 +0200 Subject: [PATCH 12/14] imported OpenPypeSecureRegistry in pype.lib.__init__ --- openpype/lib/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index 7b2f533921..ce8f8ec2b6 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -104,6 +104,7 @@ from .plugin_tools import ( from .local_settings import ( IniSettingRegistry, JSONSettingRegistry, + OpenPypeSecureRegistry, OpenPypeSettingsRegistry, get_local_site_id, change_openpype_mongo_url @@ -217,6 +218,7 @@ __all__ = [ "IniSettingRegistry", "JSONSettingRegistry", + "OpenPypeSecureRegistry", "OpenPypeSettingsRegistry", "get_local_site_id", "change_openpype_mongo_url", From 261e1db2c0751b29df870c190e9ce75cda9eeadf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 17:15:26 +0200 Subject: [PATCH 13/14] changed keyring key of mongodb data to OpenPype/mongodb --- igniter/bootstrap_repos.py | 2 +- igniter/install_dialog.py | 2 +- openpype/lib/local_settings.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 51dec7f51e..f624b96125 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -242,7 +242,7 @@ class BootstrapRepos: self._app = "openpype" self._log = log.getLogger(str(__class__)) self.data_dir = Path(user_data_dir(self._app, self._vendor)) - self.secure_registry = OpenPypeSecureRegistry("Settings") + self.secure_registry = OpenPypeSecureRegistry("mongodb") self.registry = OpenPypeSettingsRegistry() self.zip_filter = [".pyc", "__pycache__"] self.openpype_filter = [ diff --git a/igniter/install_dialog.py b/igniter/install_dialog.py index dab00079a5..27b2d1fe37 100644 --- a/igniter/install_dialog.py +++ b/igniter/install_dialog.py @@ -42,7 +42,7 @@ class InstallDialog(QtWidgets.QDialog): def __init__(self, parent=None): super(InstallDialog, self).__init__(parent) - self.secure_registry = OpenPypeSecureRegistry("Settings") + self.secure_registry = OpenPypeSecureRegistry("mongodb") self.mongo_url = "" try: diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index 1bd8540acb..c043a2f837 100644 --- a/openpype/lib/local_settings.py +++ b/openpype/lib/local_settings.py @@ -532,5 +532,5 @@ def change_openpype_mongo_url(new_mongo_url): """ validate_mongo_connection(new_mongo_url) - registry = OpenPypeSecureRegistry("Settings") + registry = OpenPypeSecureRegistry("mongodb") registry.set_item("openPypeMongo", new_mongo_url) From cbd40cd73b1dfc86f3d35a9920ba4c715b60dc41 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 8 Apr 2021 19:20:56 +0200 Subject: [PATCH 14/14] old mongo value is removed before change --- openpype/lib/local_settings.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/lib/local_settings.py b/openpype/lib/local_settings.py index c043a2f837..5d2955532a 100644 --- a/openpype/lib/local_settings.py +++ b/openpype/lib/local_settings.py @@ -106,7 +106,7 @@ class OpenPypeSecureRegistry: import keyring value = keyring.get_password(self._name, name) - if value: + if value is not None: return value if default is not _PLACEHOLDER: @@ -532,5 +532,9 @@ def change_openpype_mongo_url(new_mongo_url): """ validate_mongo_connection(new_mongo_url) + key = "openPypeMongo" registry = OpenPypeSecureRegistry("mongodb") - registry.set_item("openPypeMongo", new_mongo_url) + existing_value = registry.get_item(key, None) + if existing_value is not None: + registry.delete_item(key) + registry.set_item(key, new_mongo_url)