plugin XEP-0329: added way to change access_model using PubSub-like configuration:
Those methods are not standard, but have been done in a PubSub-like way to prepare the move to a PubSub based file sharing system.
This commit is contained in:
parent
3b5d2313a2
commit
7dd1873adf
1 changed files with 149 additions and 0 deletions
|
|
@ -58,6 +58,8 @@ IQ_FIS_REQUEST = f'{C.IQ_GET}/query[@xmlns="{NS_FIS}"]'
|
|||
# not in the standard, but needed, and it's handy to keep it here
|
||||
IQ_FIS_AFFILIATION_GET = f'{C.IQ_GET}/affiliations[@xmlns="{NS_FIS_AFFILIATION}"]'
|
||||
IQ_FIS_AFFILIATION_SET = f'{C.IQ_SET}/affiliations[@xmlns="{NS_FIS_AFFILIATION}"]'
|
||||
IQ_FIS_CONFIGURATION_GET = f'{C.IQ_GET}/configuration[@xmlns="{NS_FIS_CONFIGURATION}"]'
|
||||
IQ_FIS_CONFIGURATION_SET = f'{C.IQ_SET}/configuration[@xmlns="{NS_FIS_CONFIGURATION}"]'
|
||||
SINGLE_FILES_DIR = "files"
|
||||
TYPE_VIRTUAL = "virtual"
|
||||
TYPE_PATH = "path"
|
||||
|
|
@ -317,6 +319,22 @@ class XEP_0329(object):
|
|||
method=self._affiliationsSet,
|
||||
async_=True,
|
||||
)
|
||||
host.bridge.addMethod(
|
||||
"FISConfigurationGet",
|
||||
".plugin",
|
||||
in_sign="ssss",
|
||||
out_sign="a{ss}",
|
||||
method=self._configurationGet,
|
||||
async_=True,
|
||||
)
|
||||
host.bridge.addMethod(
|
||||
"FISConfigurationSet",
|
||||
".plugin",
|
||||
in_sign="sssa{ss}s",
|
||||
out_sign="",
|
||||
method=self._configurationSet,
|
||||
async_=True,
|
||||
)
|
||||
host.bridge.addSignal("FISSharedPathNew", ".plugin", signature="sss")
|
||||
host.bridge.addSignal("FISSharedPathRemoved", ".plugin", signature="ss")
|
||||
host.trigger.add("XEP-0234_fileSendingRequest", self._fileSendingRequestTrigger)
|
||||
|
|
@ -856,6 +874,137 @@ class XEP_0329(object):
|
|||
iq_result_elt = xmlstream.toResponse(iq_elt, "result")
|
||||
client.send(iq_result_elt)
|
||||
|
||||
# configuration
|
||||
|
||||
def _configurationGet(self, service_jid_s, namespace, path, profile):
|
||||
client = self.host.getClient(profile)
|
||||
service = jid.JID(service_jid_s)
|
||||
d = defer.ensureDeferred(self.configurationGet(
|
||||
client, service, namespace or None, path))
|
||||
d.addCallback(
|
||||
lambda configuration: {
|
||||
str(entity): affiliation for entity, affiliation in configuration.items()
|
||||
}
|
||||
)
|
||||
return d
|
||||
|
||||
async def configurationGet(
|
||||
self,
|
||||
client: SatXMPPEntity,
|
||||
service: jid.JID,
|
||||
namespace: Optional[str],
|
||||
path: str
|
||||
) -> Dict[str, str]:
|
||||
if not path:
|
||||
raise ValueError(f"invalid path: {path!r}")
|
||||
iq_elt = client.IQ("get")
|
||||
iq_elt['to'] = service.full()
|
||||
configuration_elt = iq_elt.addElement((NS_FIS_CONFIGURATION, "configuration"))
|
||||
if namespace:
|
||||
configuration_elt["namespace"] = namespace
|
||||
configuration_elt["path"] = path
|
||||
iq_result_elt = await iq_elt.send()
|
||||
try:
|
||||
configuration_elt = next(iq_result_elt.elements(NS_FIS_CONFIGURATION, "configuration"))
|
||||
except StopIteration:
|
||||
raise exceptions.DataError(f"Invalid result to configuration request: {iq_result_elt.toXml()}")
|
||||
|
||||
form = data_form.findForm(configuration_elt, NS_FIS_CONFIGURATION)
|
||||
configuration = {f.var: f.value for f in form.fields.values()}
|
||||
|
||||
return configuration
|
||||
|
||||
def _configurationSet(self, service_jid_s, namespace, path, configuration, profile):
|
||||
client = self.host.getClient(profile)
|
||||
service = jid.JID(service_jid_s)
|
||||
return defer.ensureDeferred(self.configurationSet(
|
||||
client, service, namespace or None, path, configuration))
|
||||
|
||||
async def configurationSet(
|
||||
self,
|
||||
client: SatXMPPEntity,
|
||||
service: jid.JID,
|
||||
namespace: Optional[str],
|
||||
path: str,
|
||||
configuration: Dict[jid.JID, str],
|
||||
):
|
||||
if not path:
|
||||
raise ValueError(f"invalid path: {path!r}")
|
||||
iq_elt = client.IQ("set")
|
||||
iq_elt['to'] = service.full()
|
||||
configuration_elt = iq_elt.addElement((NS_FIS_CONFIGURATION, "configuration"))
|
||||
if namespace:
|
||||
configuration_elt["namespace"] = namespace
|
||||
configuration_elt["path"] = path
|
||||
form = data_form.Form(formType="submit", formNamespace=NS_FIS_CONFIGURATION)
|
||||
form.makeFields(configuration)
|
||||
configuration_elt.addChild(form.toElement())
|
||||
await iq_elt.send()
|
||||
|
||||
def _onComponentConfigurationGet(self, iq_elt, client):
|
||||
iq_elt.handled = True
|
||||
defer.ensureDeferred(self.onComponentConfigurationGet(client, iq_elt))
|
||||
|
||||
async def onComponentConfigurationGet(self, client, iq_elt):
|
||||
try:
|
||||
(
|
||||
from_jid, configuration_elt, path, namespace, file_data
|
||||
) = await self._parseElement(client, iq_elt, "configuration", NS_FIS_CONFIGURATION)
|
||||
except exceptions.CancelError:
|
||||
return
|
||||
except RootPathException:
|
||||
client.sendError(iq_elt, 'bad-request', "Root path can't be used")
|
||||
return
|
||||
try:
|
||||
access_type = file_data['access'][C.ACCESS_PERM_READ]['type']
|
||||
except KeyError:
|
||||
access_model = 'whitelist'
|
||||
else:
|
||||
access_model = 'open' if access_type == C.ACCESS_TYPE_PUBLIC else 'whitelist'
|
||||
|
||||
iq_result_elt = xmlstream.toResponse(iq_elt, "result")
|
||||
configuration_elt = iq_result_elt.addElement((NS_FIS_CONFIGURATION, 'configuration'))
|
||||
form = data_form.Form(formType="form", formNamespace=NS_FIS_CONFIGURATION)
|
||||
form.makeFields({'access_model': access_model})
|
||||
configuration_elt.addChild(form.toElement())
|
||||
client.send(iq_result_elt)
|
||||
|
||||
def _onComponentConfigurationSet(self, iq_elt, client):
|
||||
iq_elt.handled = True
|
||||
defer.ensureDeferred(self.onComponentConfigurationSet(client, iq_elt))
|
||||
|
||||
async def onComponentConfigurationSet(self, client, iq_elt):
|
||||
try:
|
||||
(
|
||||
from_jid, configuration_elt, path, namespace, file_data
|
||||
) = await self._parseElement(client, iq_elt, "configuration", NS_FIS_CONFIGURATION)
|
||||
except exceptions.CancelError:
|
||||
return
|
||||
except RootPathException:
|
||||
client.sendError(iq_elt, 'bad-request', "Root path can't be used")
|
||||
return
|
||||
|
||||
from_jid_bare = from_jid.userhostJID()
|
||||
is_owner = from_jid_bare == file_data.get('owner')
|
||||
if not is_owner:
|
||||
log.warning(
|
||||
f"{from_jid} tried to modify {path} configuration while the owner is "
|
||||
f"{file_data['owner']}"
|
||||
)
|
||||
client.sendError(iq_elt, 'forbidden')
|
||||
return
|
||||
|
||||
form = data_form.findForm(configuration_elt, NS_FIS_CONFIGURATION)
|
||||
for name, value in form.items():
|
||||
if name == 'access_model':
|
||||
await self.host.memory.setFileAccessModel(client, file_data, value)
|
||||
else:
|
||||
# TODO: send a IQ error?
|
||||
log.warning(
|
||||
f"Trying to set a not implemented configuration option: {name}")
|
||||
iq_result_elt = xmlstream.toResponse(iq_elt, "result")
|
||||
client.send(iq_result_elt)
|
||||
|
||||
# file methods #
|
||||
|
||||
def _serializeData(self, files_data):
|
||||
|
|
|
|||
Loading…
Reference in a new issue