diff --git a/sat/bridge/bridge_constructor/bridge_template.ini b/sat/bridge/bridge_constructor/bridge_template.ini index 0c5c9d05..56911959 100644 --- a/sat/bridge/bridge_constructor/bridge_template.ini +++ b/sat/bridge/bridge_constructor/bridge_template.ini @@ -573,6 +573,41 @@ doc_param_1=category: as for [setParam] doc_param_2=attribute: Name of the attribute doc_param_3=%(doc_profile_key)s +[privateDataGet] +async= +type=method +category=core +sig_in=sss +sig_out=s +doc=Retrieve private data +doc_param_0=namespace: unique namespace to use +doc_param_1=key: key of the data to set +doc_param_2=%(doc_profile_key)s +doc_return=serialised data + +[privateDataSet] +async= +type=method +category=core +sig_in=ssss +sig_out= +doc=Store private data +doc_param_0=namespace: unique namespace to use +doc_param_1=key: key of the data to set +doc_param_2=data: serialised data +doc_param_3=%(doc_profile_key)s + +[privateDataDelete] +async= +type=method +category=core +sig_in=sss +sig_out= +doc=Delete private data +doc_param_0=namespace: unique namespace to use +doc_param_1=key: key of the data to delete +doc_param_3=%(doc_profile_key)s + [asyncGetParamA] async= type=method diff --git a/sat/bridge/dbus_bridge.py b/sat/bridge/dbus_bridge.py index 29191bfc..ae603c22 100644 --- a/sat/bridge/dbus_bridge.py +++ b/sat/bridge/dbus_bridge.py @@ -474,6 +474,24 @@ class DbusObject(dbus.service.Object): def paramsRegisterApp(self, xml, security_limit=-1, app=''): return self._callback("paramsRegisterApp", str(xml), security_limit, str(app)) + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='sss', out_signature='', + async_callbacks=('callback', 'errback')) + def privateDataDelete(self, namespace, key, arg_2, callback=None, errback=None): + return self._callback("privateDataDelete", str(namespace), str(key), str(arg_2), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='sss', out_signature='s', + async_callbacks=('callback', 'errback')) + def privateDataGet(self, namespace, key, profile_key, callback=None, errback=None): + return self._callback("privateDataGet", str(namespace), str(key), str(profile_key), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ssss', out_signature='', + async_callbacks=('callback', 'errback')) + def privateDataSet(self, namespace, key, data, profile_key, callback=None, errback=None): + return self._callback("privateDataSet", str(namespace), str(key), str(data), str(profile_key), callback=callback, errback=errback) + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, in_signature='sss', out_signature='', async_callbacks=('callback', 'errback')) diff --git a/sat/core/sat_main.py b/sat/core/sat_main.py index 36bd7ff7..87017541 100644 --- a/sat/core/sat_main.py +++ b/sat/core/sat_main.py @@ -136,6 +136,9 @@ class SAT(service.Service): self.bridge.register_method("getConfig", self._getConfig) self.bridge.register_method("setParam", self.setParam) self.bridge.register_method("getParamA", self.memory.getStringParamA) + self.bridge.register_method("privateDataGet", self.memory._privateDataGet) + self.bridge.register_method("privateDataSet", self.memory._privateDataSet) + self.bridge.register_method("privateDataDelete", self.memory._privateDataDelete) self.bridge.register_method("asyncGetParamA", self.memory.asyncGetStringParamA) self.bridge.register_method( "asyncGetParamsValuesFromCategory", diff --git a/sat/memory/memory.py b/sat/memory/memory.py index 9a6daedc..435a1a08 100644 --- a/sat/memory/memory.py +++ b/sat/memory/memory.py @@ -39,6 +39,7 @@ from sat.memory.disco import Discovery from sat.memory.crypto import BlockCipher from sat.memory.crypto import PasswordHasher from sat.tools import config as tools_config +from sat.tools.common import data_format import shortuuid import mimetypes import time @@ -1153,6 +1154,27 @@ class Memory(object): def setDefault(self, name, category, callback, errback=None): return self.params.setDefault(name, category, callback, errback) + ## Private Data ## + + def _privateDataSet(self, namespace, key, data_s, profile_key): + client = self.host.getClient(profile_key) + # we accept any type + data = data_format.deserialise(data_s, type_check=None) + return self.storage.setPrivateValue( + namespace, key, data, binary=True, profile=client.profile) + + def _privateDataGet(self, namespace, key, profile_key): + client = self.host.getClient(profile_key) + d = self.storage.getPrivates( + namespace, [key], binary=True, profile=client.profile) + d.addCallback(lambda data_dict: data_format.serialise(data_dict.get(key))) + return d + + def _privateDataDelete(self, namespace, key, profile_key): + client = self.host.getClient(profile_key) + return self.storage.delPrivateValue( + namespace, key, binary=True, profile=client.profile) + ## Files ## def checkFilePermission(self, file_data, peer_jid, perms_to_check): diff --git a/sat_frontends/bridge/dbus_bridge.py b/sat_frontends/bridge/dbus_bridge.py index 09c2f4bf..0d404413 100644 --- a/sat_frontends/bridge/dbus_bridge.py +++ b/sat_frontends/bridge/dbus_bridge.py @@ -641,6 +641,33 @@ class Bridge: kwargs['error_handler'] = error_handler return self.db_core_iface.paramsRegisterApp(xml, security_limit, app, **kwargs) + def privateDataDelete(self, namespace, key, arg_2, callback=None, errback=None): + if callback is None: + error_handler = None + else: + if errback is None: + errback = log.error + error_handler = lambda err:errback(dbus_to_bridge_exception(err)) + return self.db_core_iface.privateDataDelete(namespace, key, arg_2, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def privateDataGet(self, namespace, key, profile_key, callback=None, errback=None): + if callback is None: + error_handler = None + else: + if errback is None: + errback = log.error + error_handler = lambda err:errback(dbus_to_bridge_exception(err)) + return str(self.db_core_iface.privateDataGet(namespace, key, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler)) + + def privateDataSet(self, namespace, key, data, profile_key, callback=None, errback=None): + if callback is None: + error_handler = None + else: + if errback is None: + errback = log.error + error_handler = lambda err:errback(dbus_to_bridge_exception(err)) + return self.db_core_iface.privateDataSet(namespace, key, data, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + def profileCreate(self, profile, password='', component='', callback=None, errback=None): if callback is None: error_handler = None @@ -1226,6 +1253,30 @@ class AIOBridge(Bridge): self.db_core_iface.paramsRegisterApp(xml, security_limit, app, timeout=const_TIMEOUT, reply_handler=reply_handler, error_handler=error_handler) return fut + def privateDataDelete(self, namespace, key, arg_2): + loop = asyncio.get_running_loop() + fut = loop.create_future() + reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) + error_handler = lambda err: loop.call_soon_threadsafe(fut.set_exception, dbus_to_bridge_exception(err)) + self.db_core_iface.privateDataDelete(namespace, key, arg_2, timeout=const_TIMEOUT, reply_handler=reply_handler, error_handler=error_handler) + return fut + + def privateDataGet(self, namespace, key, profile_key): + loop = asyncio.get_running_loop() + fut = loop.create_future() + reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) + error_handler = lambda err: loop.call_soon_threadsafe(fut.set_exception, dbus_to_bridge_exception(err)) + self.db_core_iface.privateDataGet(namespace, key, profile_key, timeout=const_TIMEOUT, reply_handler=reply_handler, error_handler=error_handler) + return fut + + def privateDataSet(self, namespace, key, data, profile_key): + loop = asyncio.get_running_loop() + fut = loop.create_future() + reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) + error_handler = lambda err: loop.call_soon_threadsafe(fut.set_exception, dbus_to_bridge_exception(err)) + self.db_core_iface.privateDataSet(namespace, key, data, profile_key, timeout=const_TIMEOUT, reply_handler=reply_handler, error_handler=error_handler) + return fut + def profileCreate(self, profile, password='', component=''): loop = asyncio.get_running_loop() fut = loop.create_future() diff --git a/sat_frontends/bridge/pb.py b/sat_frontends/bridge/pb.py index 35e60b15..949222c4 100644 --- a/sat_frontends/bridge/pb.py +++ b/sat_frontends/bridge/pb.py @@ -487,6 +487,30 @@ class Bridge(object): errback = self._generic_errback d.addErrback(errback) + def privateDataDelete(self, namespace, key, arg_2, callback=None, errback=None): + d = self.root.callRemote("privateDataDelete", namespace, key, arg_2) + if callback is not None: + d.addCallback(lambda __: callback()) + if errback is None: + errback = self._generic_errback + d.addErrback(errback) + + def privateDataGet(self, namespace, key, profile_key, callback=None, errback=None): + d = self.root.callRemote("privateDataGet", namespace, key, profile_key) + if callback is not None: + d.addCallback(callback) + if errback is None: + errback = self._generic_errback + d.addErrback(errback) + + def privateDataSet(self, namespace, key, data, profile_key, callback=None, errback=None): + d = self.root.callRemote("privateDataSet", namespace, key, data, profile_key) + if callback is not None: + d.addCallback(lambda __: callback()) + if errback is None: + errback = self._generic_errback + d.addErrback(errback) + def profileCreate(self, profile, password='', component='', callback=None, errback=None): d = self.root.callRemote("profileCreate", profile, password, component) if callback is not None: @@ -859,6 +883,21 @@ class AIOBridge(Bridge): d.addErrback(self._errback) return d.asFuture(asyncio.get_event_loop()) + def privateDataDelete(self, namespace, key, arg_2): + d = self.root.callRemote("privateDataDelete", namespace, key, arg_2) + d.addErrback(self._errback) + return d.asFuture(asyncio.get_event_loop()) + + def privateDataGet(self, namespace, key, profile_key): + d = self.root.callRemote("privateDataGet", namespace, key, profile_key) + d.addErrback(self._errback) + return d.asFuture(asyncio.get_event_loop()) + + def privateDataSet(self, namespace, key, data, profile_key): + d = self.root.callRemote("privateDataSet", namespace, key, data, profile_key) + d.addErrback(self._errback) + return d.asFuture(asyncio.get_event_loop()) + def profileCreate(self, profile, password='', component=''): d = self.root.callRemote("profileCreate", profile, password, component) d.addErrback(self._errback)