comparison libervia/backend/plugins/plugin_xep_0329.py @ 4270:0d7bb4df2343

Reformatted code base using black.
author Goffi <goffi@goffi.org>
date Wed, 19 Jun 2024 18:44:57 +0200
parents 4b842c1fb686
children
comparison
equal deleted inserted replaced
4269:64a85ce8be70 4270:0d7bb4df2343
207 @raise NotFound: path lead to a non existing file/directory 207 @raise NotFound: path lead to a non existing file/directory
208 """ 208 """
209 path_elts = [_f for _f in path.split("/") if _f] 209 path_elts = [_f for _f in path.split("/") if _f]
210 210
211 if ".." in path_elts: 211 if ".." in path_elts:
212 log.warning(_( 212 log.warning(
213 'parent dir ("..") found in path, hack attempt? path is {path} ' 213 _(
214 '[{profile}]').format(path=path, profile=client.profile)) 214 'parent dir ("..") found in path, hack attempt? path is {path} '
215 "[{profile}]"
216 ).format(path=path, profile=client.profile)
217 )
215 raise exceptions.PermissionError("illegal path elements") 218 raise exceptions.PermissionError("illegal path elements")
216 219
217 node = client._XEP_0329_root_node 220 node = client._XEP_0329_root_node
218 221
219 while path_elts: 222 while path_elts:
345 method=self._create_dir, 348 method=self._create_dir,
346 async_=True, 349 async_=True,
347 ) 350 )
348 host.bridge.add_signal("fis_shared_path_new", ".plugin", signature="sss") 351 host.bridge.add_signal("fis_shared_path_new", ".plugin", signature="sss")
349 host.bridge.add_signal("fis_shared_path_removed", ".plugin", signature="ss") 352 host.bridge.add_signal("fis_shared_path_removed", ".plugin", signature="ss")
350 host.trigger.add("XEP-0234_fileSendingRequest", self._file_sending_request_trigger) 353 host.trigger.add(
354 "XEP-0234_fileSendingRequest", self._file_sending_request_trigger
355 )
351 host.register_namespace("fis", NS_FIS) 356 host.register_namespace("fis", NS_FIS)
352 357
353 def get_handler(self, client): 358 def get_handler(self, client):
354 return XEP_0329_handler(self) 359 return XEP_0329_handler(self)
355 360
356 def profile_connected(self, client): 361 def profile_connected(self, client):
357 if client.is_component: 362 if client.is_component:
358 client._file_sharing_allowed_hosts = self.host.memory.config_get( 363 client._file_sharing_allowed_hosts = self.host.memory.config_get(
359 'component file_sharing', 364 "component file_sharing", "http_upload_allowed_hosts_list"
360 'http_upload_allowed_hosts_list') or [client.host] 365 ) or [client.host]
361 else: 366 else:
362 client._XEP_0329_root_node = ShareNode( 367 client._XEP_0329_root_node = ShareNode(
363 None, 368 None,
364 None, 369 None,
365 TYPE_VIRTUAL, 370 TYPE_VIRTUAL,
475 name = os.path.basename(path) 480 name = os.path.basename(path)
476 if os.path.isfile(path): 481 if os.path.isfile(path):
477 size = os.path.getsize(path) 482 size = os.path.getsize(path)
478 mime_type = mimetypes.guess_type(path, strict=False)[0] 483 mime_type = mimetypes.guess_type(path, strict=False)[0]
479 file_elt = self._jf.build_file_element( 484 file_elt = self._jf.build_file_element(
480 client=client, name=name, size=size, mime_type=mime_type, 485 client=client,
481 modified=os.path.getmtime(path) 486 name=name,
487 size=size,
488 mime_type=mime_type,
489 modified=os.path.getmtime(path),
482 ) 490 )
483 491
484 query_elt.addChild(file_elt) 492 query_elt.addChild(file_elt)
485 # we don't specify hash as it would be too resource intensive to calculate 493 # we don't specify hash as it would be too resource intensive to calculate
486 # it for all files. 494 # it for all files.
623 ) 631 )
624 except exceptions.NotFound: 632 except exceptions.NotFound:
625 self._iq_error(client, iq_elt) 633 self._iq_error(client, iq_elt)
626 return 634 return
627 except exceptions.PermissionError: 635 except exceptions.PermissionError:
628 self._iq_error(client, iq_elt, condition='not-allowed') 636 self._iq_error(client, iq_elt, condition="not-allowed")
629 return 637 return
630 except Exception as e: 638 except Exception as e:
631 tb = traceback.format_tb(e.__traceback__) 639 tb = traceback.format_tb(e.__traceback__)
632 log.error(f"internal server error: {e}\n{''.join(tb)}") 640 log.error(f"internal server error: {e}\n{''.join(tb)}")
633 self._iq_error(client, iq_elt, condition='internal-server-error') 641 self._iq_error(client, iq_elt, condition="internal-server-error")
634 return 642 return
635 iq_result_elt = xmlstream.toResponse(iq_elt, "result") 643 iq_result_elt = xmlstream.toResponse(iq_elt, "result")
636 query_elt = iq_result_elt.addElement((NS_FIS, "query")) 644 query_elt = iq_result_elt.addElement((NS_FIS, "query"))
637 query_elt["node"] = node_path 645 query_elt["node"] = node_path
638 if not self.host.trigger.point( 646 if not self.host.trigger.point(
640 client, 648 client,
641 iq_elt, 649 iq_elt,
642 iq_result_elt, 650 iq_result_elt,
643 owner, 651 owner,
644 node_path, 652 node_path,
645 files_data 653 files_data,
646 ): 654 ):
647 return 655 return
648 for file_data in files_data: 656 for file_data in files_data:
649 if file_data['type'] == C.FILE_TYPE_DIRECTORY: 657 if file_data["type"] == C.FILE_TYPE_DIRECTORY:
650 directory_elt = query_elt.addElement("directory") 658 directory_elt = query_elt.addElement("directory")
651 directory_elt['name'] = file_data['name'] 659 directory_elt["name"] = file_data["name"]
652 self.host.trigger.point( 660 self.host.trigger.point(
653 "XEP-0329_compGetFilesFromNode_build_directory", 661 "XEP-0329_compGetFilesFromNode_build_directory",
654 client, 662 client,
655 file_data, 663 file_data,
656 directory_elt, 664 directory_elt,
659 ) 667 )
660 else: 668 else:
661 file_elt = self._jf.build_file_element_from_dict( 669 file_elt = self._jf.build_file_element_from_dict(
662 client, 670 client,
663 file_data, 671 file_data,
664 modified=file_data.get("modified", file_data["created"]) 672 modified=file_data.get("modified", file_data["created"]),
665 ) 673 )
666 query_elt.addChild(file_elt) 674 query_elt.addChild(file_elt)
667 client.send(iq_result_elt) 675 client.send(iq_result_elt)
668 676
669 def on_component_request(self, iq_elt, client): 677 def on_component_request(self, iq_elt, client):
670 return self._request_handler( 678 return self._request_handler(
671 client, iq_elt, self._comp_get_root_nodes_cb, self._comp_get_files_from_node_cb 679 client,
680 iq_elt,
681 self._comp_get_root_nodes_cb,
682 self._comp_get_files_from_node_cb,
672 ) 683 )
673 684
674 async def _parse_result(self, client, peer_jid, iq_elt): 685 async def _parse_result(self, client, peer_jid, iq_elt):
675 query_elt = next(iq_elt.elements(NS_FIS, "query")) 686 query_elt = next(iq_elt.elements(NS_FIS, "query"))
676 files = [] 687 files = []
682 file_data = await self._jf.parse_file_element(client, elt) 693 file_data = await self._jf.parse_file_element(client, elt)
683 except exceptions.DataError: 694 except exceptions.DataError:
684 continue 695 continue
685 file_data["type"] = C.FILE_TYPE_FILE 696 file_data["type"] = C.FILE_TYPE_FILE
686 try: 697 try:
687 thumbs = file_data['extra'][C.KEY_THUMBNAILS] 698 thumbs = file_data["extra"][C.KEY_THUMBNAILS]
688 except KeyError: 699 except KeyError:
689 log.debug(f"No thumbnail found for {file_data}") 700 log.debug(f"No thumbnail found for {file_data}")
690 else: 701 else:
691 for thumb in thumbs: 702 for thumb in thumbs:
692 if 'url' not in thumb and "id" in thumb: 703 if "url" not in thumb and "id" in thumb:
693 try: 704 try:
694 file_path = await self._b.get_file(client, peer_jid, thumb['id']) 705 file_path = await self._b.get_file(
706 client, peer_jid, thumb["id"]
707 )
695 except Exception as e: 708 except Exception as e:
696 log.warning(f"Can't get thumbnail {thumb['id']!r} for {file_data}: {e}") 709 log.warning(
710 f"Can't get thumbnail {thumb['id']!r} for {file_data}: {e}"
711 )
697 else: 712 else:
698 thumb['filename'] = file_path.name 713 thumb["filename"] = file_path.name
699 714
700 elif elt.name == "directory" and elt.uri == NS_FIS: 715 elif elt.name == "directory" and elt.uri == NS_FIS:
701 # we have a directory 716 # we have a directory
702 717
703 file_data = {"name": elt["name"], "type": C.FILE_TYPE_DIRECTORY} 718 file_data = {"name": elt["name"], "type": C.FILE_TYPE_DIRECTORY}
707 elt, 722 elt,
708 file_data, 723 file_data,
709 ) 724 )
710 else: 725 else:
711 log.warning( 726 log.warning(
712 _("unexpected element, ignoring: {elt}") 727 _("unexpected element, ignoring: {elt}").format(elt=elt.toXml())
713 .format(elt=elt.toXml())
714 ) 728 )
715 continue 729 continue
716 files.append(file_data) 730 files.append(file_data)
717 return files 731 return files
718 732
719 # affiliations # 733 # affiliations #
720 734
721 async def _parse_element(self, client, iq_elt, element, namespace): 735 async def _parse_element(self, client, iq_elt, element, namespace):
722 peer_jid, owner = client.get_owner_and_peer(iq_elt) 736 peer_jid, owner = client.get_owner_and_peer(iq_elt)
723 elt = next(iq_elt.elements(namespace, element)) 737 elt = next(iq_elt.elements(namespace, element))
724 path = Path("/", elt['path']) 738 path = Path("/", elt["path"])
725 if len(path.parts) < 2: 739 if len(path.parts) < 2:
726 raise RootPathException 740 raise RootPathException
727 namespace = elt.getAttribute('namespace') 741 namespace = elt.getAttribute("namespace")
728 files_data = await self.host.memory.get_files( 742 files_data = await self.host.memory.get_files(
729 client, 743 client,
730 peer_jid=peer_jid, 744 peer_jid=peer_jid,
731 path=str(path.parent), 745 path=str(path.parent),
732 name=path.name, 746 name=path.name,
733 namespace=namespace, 747 namespace=namespace,
734 owner=owner, 748 owner=owner,
735 ) 749 )
736 if len(files_data) != 1: 750 if len(files_data) != 1:
737 client.sendError(iq_elt, 'item-not-found') 751 client.sendError(iq_elt, "item-not-found")
738 raise exceptions.CancelError 752 raise exceptions.CancelError
739 file_data = files_data[0] 753 file_data = files_data[0]
740 return peer_jid, elt, path, namespace, file_data 754 return peer_jid, elt, path, namespace, file_data
741 755
742 def _affiliations_get(self, service_jid_s, namespace, path, profile): 756 def _affiliations_get(self, service_jid_s, namespace, path, profile):
743 client = self.host.get_client(profile) 757 client = self.host.get_client(profile)
744 service = jid.JID(service_jid_s) 758 service = jid.JID(service_jid_s)
745 d = defer.ensureDeferred(self.affiliationsGet( 759 d = defer.ensureDeferred(
746 client, service, namespace or None, path)) 760 self.affiliationsGet(client, service, namespace or None, path)
761 )
747 d.addCallback( 762 d.addCallback(
748 lambda affiliations: { 763 lambda affiliations: {
749 str(entity): affiliation for entity, affiliation in affiliations.items() 764 str(entity): affiliation for entity, affiliation in affiliations.items()
750 } 765 }
751 ) 766 )
752 return d 767 return d
753 768
754 async def affiliationsGet( 769 async def affiliationsGet(
755 self, 770 self, client: SatXMPPEntity, service: jid.JID, namespace: Optional[str], path: str
756 client: SatXMPPEntity,
757 service: jid.JID,
758 namespace: Optional[str],
759 path: str
760 ) -> Dict[jid.JID, str]: 771 ) -> Dict[jid.JID, str]:
761 if not path: 772 if not path:
762 raise ValueError(f"invalid path: {path!r}") 773 raise ValueError(f"invalid path: {path!r}")
763 iq_elt = client.IQ("get") 774 iq_elt = client.IQ("get")
764 iq_elt['to'] = service.full() 775 iq_elt["to"] = service.full()
765 affiliations_elt = iq_elt.addElement((NS_FIS_AFFILIATION, "affiliations")) 776 affiliations_elt = iq_elt.addElement((NS_FIS_AFFILIATION, "affiliations"))
766 if namespace: 777 if namespace:
767 affiliations_elt["namespace"] = namespace 778 affiliations_elt["namespace"] = namespace
768 affiliations_elt["path"] = path 779 affiliations_elt["path"] = path
769 iq_result_elt = await iq_elt.send() 780 iq_result_elt = await iq_elt.send()
770 try: 781 try:
771 affiliations_elt = next(iq_result_elt.elements(NS_FIS_AFFILIATION, "affiliations")) 782 affiliations_elt = next(
783 iq_result_elt.elements(NS_FIS_AFFILIATION, "affiliations")
784 )
772 except StopIteration: 785 except StopIteration:
773 raise exceptions.DataError(f"Invalid result to affiliations request: {iq_result_elt.toXml()}") 786 raise exceptions.DataError(
787 f"Invalid result to affiliations request: {iq_result_elt.toXml()}"
788 )
774 789
775 affiliations = {} 790 affiliations = {}
776 for affiliation_elt in affiliations_elt.elements(NS_FIS_AFFILIATION, 'affiliation'): 791 for affiliation_elt in affiliations_elt.elements(
792 NS_FIS_AFFILIATION, "affiliation"
793 ):
777 try: 794 try:
778 affiliations[jid.JID(affiliation_elt['jid'])] = affiliation_elt['affiliation'] 795 affiliations[jid.JID(affiliation_elt["jid"])] = affiliation_elt[
796 "affiliation"
797 ]
779 except (KeyError, RuntimeError): 798 except (KeyError, RuntimeError):
780 raise exceptions.DataError( 799 raise exceptions.DataError(
781 f"invalid affiliation element: {affiliation_elt.toXml()}") 800 f"invalid affiliation element: {affiliation_elt.toXml()}"
801 )
782 802
783 return affiliations 803 return affiliations
784 804
785 def _affiliations_set(self, service_jid_s, namespace, path, affiliations, profile): 805 def _affiliations_set(self, service_jid_s, namespace, path, affiliations, profile):
786 client = self.host.get_client(profile) 806 client = self.host.get_client(profile)
787 service = jid.JID(service_jid_s) 807 service = jid.JID(service_jid_s)
788 affiliations = {jid.JID(e): a for e, a in affiliations.items()} 808 affiliations = {jid.JID(e): a for e, a in affiliations.items()}
789 return defer.ensureDeferred(self.affiliationsSet( 809 return defer.ensureDeferred(
790 client, service, namespace or None, path, affiliations)) 810 self.affiliationsSet(client, service, namespace or None, path, affiliations)
811 )
791 812
792 async def affiliationsSet( 813 async def affiliationsSet(
793 self, 814 self,
794 client: SatXMPPEntity, 815 client: SatXMPPEntity,
795 service: jid.JID, 816 service: jid.JID,
798 affiliations: Dict[jid.JID, str], 819 affiliations: Dict[jid.JID, str],
799 ): 820 ):
800 if not path: 821 if not path:
801 raise ValueError(f"invalid path: {path!r}") 822 raise ValueError(f"invalid path: {path!r}")
802 iq_elt = client.IQ("set") 823 iq_elt = client.IQ("set")
803 iq_elt['to'] = service.full() 824 iq_elt["to"] = service.full()
804 affiliations_elt = iq_elt.addElement((NS_FIS_AFFILIATION, "affiliations")) 825 affiliations_elt = iq_elt.addElement((NS_FIS_AFFILIATION, "affiliations"))
805 if namespace: 826 if namespace:
806 affiliations_elt["namespace"] = namespace 827 affiliations_elt["namespace"] = namespace
807 affiliations_elt["path"] = path 828 affiliations_elt["path"] = path
808 for entity_jid, affiliation in affiliations.items(): 829 for entity_jid, affiliation in affiliations.items():
809 affiliation_elt = affiliations_elt.addElement('affiliation') 830 affiliation_elt = affiliations_elt.addElement("affiliation")
810 affiliation_elt['jid'] = entity_jid.full() 831 affiliation_elt["jid"] = entity_jid.full()
811 affiliation_elt['affiliation'] = affiliation 832 affiliation_elt["affiliation"] = affiliation
812 await iq_elt.send() 833 await iq_elt.send()
813 834
814 def _on_component_affiliations_get(self, iq_elt, client): 835 def _on_component_affiliations_get(self, iq_elt, client):
815 iq_elt.handled = True 836 iq_elt.handled = True
816 defer.ensureDeferred(self.on_component_affiliations_get(client, iq_elt)) 837 defer.ensureDeferred(self.on_component_affiliations_get(client, iq_elt))
817 838
818 async def on_component_affiliations_get(self, client, iq_elt): 839 async def on_component_affiliations_get(self, client, iq_elt):
819 try: 840 try:
820 ( 841 (from_jid, affiliations_elt, path, namespace, file_data) = (
821 from_jid, affiliations_elt, path, namespace, file_data 842 await self._parse_element(
822 ) = await self._parse_element(client, iq_elt, "affiliations", NS_FIS_AFFILIATION) 843 client, iq_elt, "affiliations", NS_FIS_AFFILIATION
844 )
845 )
823 except exceptions.CancelError: 846 except exceptions.CancelError:
824 return 847 return
825 except RootPathException: 848 except RootPathException:
826 # if root path is requested, we only get owner affiliation 849 # if root path is requested, we only get owner affiliation
827 peer_jid, owner = client.get_owner_and_peer(iq_elt) 850 peer_jid, owner = client.get_owner_and_peer(iq_elt)
828 is_owner = peer_jid.userhostJID() == owner 851 is_owner = peer_jid.userhostJID() == owner
829 affiliations = {owner: 'owner'} 852 affiliations = {owner: "owner"}
830 except exceptions.NotFound: 853 except exceptions.NotFound:
831 client.sendError(iq_elt, "item-not-found") 854 client.sendError(iq_elt, "item-not-found")
832 return 855 return
833 except Exception as e: 856 except Exception as e:
834 client.sendError(iq_elt, "internal-server-error", str(e)) 857 client.sendError(iq_elt, "internal-server-error", str(e))
835 return 858 return
836 else: 859 else:
837 from_jid_bare = from_jid.userhostJID() 860 from_jid_bare = from_jid.userhostJID()
838 is_owner = from_jid_bare == file_data.get('owner') 861 is_owner = from_jid_bare == file_data.get("owner")
839 affiliations = self.host.memory.get_file_affiliations(file_data) 862 affiliations = self.host.memory.get_file_affiliations(file_data)
840 iq_result_elt = xmlstream.toResponse(iq_elt, "result") 863 iq_result_elt = xmlstream.toResponse(iq_elt, "result")
841 affiliations_elt = iq_result_elt.addElement((NS_FIS_AFFILIATION, 'affiliations')) 864 affiliations_elt = iq_result_elt.addElement((NS_FIS_AFFILIATION, "affiliations"))
842 for entity_jid, affiliation in affiliations.items(): 865 for entity_jid, affiliation in affiliations.items():
843 if not is_owner and entity_jid.userhostJID() != from_jid_bare: 866 if not is_owner and entity_jid.userhostJID() != from_jid_bare:
844 # only onwer can get all affiliations 867 # only onwer can get all affiliations
845 continue 868 continue
846 affiliation_elt = affiliations_elt.addElement('affiliation') 869 affiliation_elt = affiliations_elt.addElement("affiliation")
847 affiliation_elt['jid'] = entity_jid.userhost() 870 affiliation_elt["jid"] = entity_jid.userhost()
848 affiliation_elt['affiliation'] = affiliation 871 affiliation_elt["affiliation"] = affiliation
849 client.send(iq_result_elt) 872 client.send(iq_result_elt)
850 873
851 def _on_component_affiliations_set(self, iq_elt, client): 874 def _on_component_affiliations_set(self, iq_elt, client):
852 iq_elt.handled = True 875 iq_elt.handled = True
853 defer.ensureDeferred(self.on_component_affiliations_set(client, iq_elt)) 876 defer.ensureDeferred(self.on_component_affiliations_set(client, iq_elt))
854 877
855 async def on_component_affiliations_set(self, client, iq_elt): 878 async def on_component_affiliations_set(self, client, iq_elt):
856 try: 879 try:
857 ( 880 (from_jid, affiliations_elt, path, namespace, file_data) = (
858 from_jid, affiliations_elt, path, namespace, file_data 881 await self._parse_element(
859 ) = await self._parse_element(client, iq_elt, "affiliations", NS_FIS_AFFILIATION) 882 client, iq_elt, "affiliations", NS_FIS_AFFILIATION
883 )
884 )
860 except exceptions.CancelError: 885 except exceptions.CancelError:
861 return 886 return
862 except RootPathException: 887 except RootPathException:
863 client.sendError(iq_elt, 'bad-request', "Root path can't be used") 888 client.sendError(iq_elt, "bad-request", "Root path can't be used")
864 return 889 return
865 890
866 if from_jid.userhostJID() != file_data['owner']: 891 if from_jid.userhostJID() != file_data["owner"]:
867 log.warning( 892 log.warning(
868 f"{from_jid} tried to modify {path} affiliations while the owner is " 893 f"{from_jid} tried to modify {path} affiliations while the owner is "
869 f"{file_data['owner']}" 894 f"{file_data['owner']}"
870 ) 895 )
871 client.sendError(iq_elt, 'forbidden') 896 client.sendError(iq_elt, "forbidden")
872 return 897 return
873 898
874 try: 899 try:
875 affiliations = { 900 affiliations = {
876 jid.JID(e['jid']): e['affiliation'] 901 jid.JID(e["jid"]): e["affiliation"]
877 for e in affiliations_elt.elements(NS_FIS_AFFILIATION, 'affiliation') 902 for e in affiliations_elt.elements(NS_FIS_AFFILIATION, "affiliation")
878 } 903 }
879 except (KeyError, RuntimeError): 904 except (KeyError, RuntimeError):
880 log.warning( 905 log.warning(f"invalid affiliation element: {affiliations_elt.toXml()}")
881 f"invalid affiliation element: {affiliations_elt.toXml()}" 906 client.sendError(iq_elt, "bad-request", "invalid affiliation element")
882 ) 907 return
883 client.sendError(iq_elt, 'bad-request', "invalid affiliation element")
884 return
885 except Exception as e: 908 except Exception as e:
886 log.error( 909 log.error(
887 f"unexepected exception while setting affiliation element: {e}\n" 910 f"unexepected exception while setting affiliation element: {e}\n"
888 f"{affiliations_elt.toXml()}" 911 f"{affiliations_elt.toXml()}"
889 ) 912 )
890 client.sendError(iq_elt, 'internal-server-error', f"{e}") 913 client.sendError(iq_elt, "internal-server-error", f"{e}")
891 return 914 return
892 915
893 await self.host.memory.set_file_affiliations(client, file_data, affiliations) 916 await self.host.memory.set_file_affiliations(client, file_data, affiliations)
894 917
895 iq_result_elt = xmlstream.toResponse(iq_elt, "result") 918 iq_result_elt = xmlstream.toResponse(iq_elt, "result")
896 client.send(iq_result_elt) 919 client.send(iq_result_elt)
898 # configuration 921 # configuration
899 922
900 def _configuration_get(self, service_jid_s, namespace, path, profile): 923 def _configuration_get(self, service_jid_s, namespace, path, profile):
901 client = self.host.get_client(profile) 924 client = self.host.get_client(profile)
902 service = jid.JID(service_jid_s) 925 service = jid.JID(service_jid_s)
903 d = defer.ensureDeferred(self.configuration_get( 926 d = defer.ensureDeferred(
904 client, service, namespace or None, path)) 927 self.configuration_get(client, service, namespace or None, path)
928 )
905 d.addCallback( 929 d.addCallback(
906 lambda configuration: { 930 lambda configuration: {
907 str(entity): affiliation for entity, affiliation in configuration.items() 931 str(entity): affiliation for entity, affiliation in configuration.items()
908 } 932 }
909 ) 933 )
910 return d 934 return d
911 935
912 async def configuration_get( 936 async def configuration_get(
913 self, 937 self, client: SatXMPPEntity, service: jid.JID, namespace: Optional[str], path: str
914 client: SatXMPPEntity,
915 service: jid.JID,
916 namespace: Optional[str],
917 path: str
918 ) -> Dict[str, str]: 938 ) -> Dict[str, str]:
919 if not path: 939 if not path:
920 raise ValueError(f"invalid path: {path!r}") 940 raise ValueError(f"invalid path: {path!r}")
921 iq_elt = client.IQ("get") 941 iq_elt = client.IQ("get")
922 iq_elt['to'] = service.full() 942 iq_elt["to"] = service.full()
923 configuration_elt = iq_elt.addElement((NS_FIS_CONFIGURATION, "configuration")) 943 configuration_elt = iq_elt.addElement((NS_FIS_CONFIGURATION, "configuration"))
924 if namespace: 944 if namespace:
925 configuration_elt["namespace"] = namespace 945 configuration_elt["namespace"] = namespace
926 configuration_elt["path"] = path 946 configuration_elt["path"] = path
927 iq_result_elt = await iq_elt.send() 947 iq_result_elt = await iq_elt.send()
928 try: 948 try:
929 configuration_elt = next(iq_result_elt.elements(NS_FIS_CONFIGURATION, "configuration")) 949 configuration_elt = next(
950 iq_result_elt.elements(NS_FIS_CONFIGURATION, "configuration")
951 )
930 except StopIteration: 952 except StopIteration:
931 raise exceptions.DataError(f"Invalid result to configuration request: {iq_result_elt.toXml()}") 953 raise exceptions.DataError(
954 f"Invalid result to configuration request: {iq_result_elt.toXml()}"
955 )
932 956
933 form = data_form.findForm(configuration_elt, NS_FIS_CONFIGURATION) 957 form = data_form.findForm(configuration_elt, NS_FIS_CONFIGURATION)
934 configuration = {f.var: f.value for f in form.fields.values()} 958 configuration = {f.var: f.value for f in form.fields.values()}
935 959
936 return configuration 960 return configuration
937 961
938 def _configuration_set(self, service_jid_s, namespace, path, configuration, profile): 962 def _configuration_set(self, service_jid_s, namespace, path, configuration, profile):
939 client = self.host.get_client(profile) 963 client = self.host.get_client(profile)
940 service = jid.JID(service_jid_s) 964 service = jid.JID(service_jid_s)
941 return defer.ensureDeferred(self.configuration_set( 965 return defer.ensureDeferred(
942 client, service, namespace or None, path, configuration)) 966 self.configuration_set(
967 client, service, namespace or None, path, configuration
968 )
969 )
943 970
944 async def configuration_set( 971 async def configuration_set(
945 self, 972 self,
946 client: SatXMPPEntity, 973 client: SatXMPPEntity,
947 service: jid.JID, 974 service: jid.JID,
950 configuration: Dict[str, str], 977 configuration: Dict[str, str],
951 ): 978 ):
952 if not path: 979 if not path:
953 raise ValueError(f"invalid path: {path!r}") 980 raise ValueError(f"invalid path: {path!r}")
954 iq_elt = client.IQ("set") 981 iq_elt = client.IQ("set")
955 iq_elt['to'] = service.full() 982 iq_elt["to"] = service.full()
956 configuration_elt = iq_elt.addElement((NS_FIS_CONFIGURATION, "configuration")) 983 configuration_elt = iq_elt.addElement((NS_FIS_CONFIGURATION, "configuration"))
957 if namespace: 984 if namespace:
958 configuration_elt["namespace"] = namespace 985 configuration_elt["namespace"] = namespace
959 configuration_elt["path"] = path 986 configuration_elt["path"] = path
960 form = data_form.Form(formType="submit", formNamespace=NS_FIS_CONFIGURATION) 987 form = data_form.Form(formType="submit", formNamespace=NS_FIS_CONFIGURATION)
966 iq_elt.handled = True 993 iq_elt.handled = True
967 defer.ensureDeferred(self.on_component_configuration_get(client, iq_elt)) 994 defer.ensureDeferred(self.on_component_configuration_get(client, iq_elt))
968 995
969 async def on_component_configuration_get(self, client, iq_elt): 996 async def on_component_configuration_get(self, client, iq_elt):
970 try: 997 try:
971 ( 998 (from_jid, configuration_elt, path, namespace, file_data) = (
972 from_jid, configuration_elt, path, namespace, file_data 999 await self._parse_element(
973 ) = await self._parse_element(client, iq_elt, "configuration", NS_FIS_CONFIGURATION) 1000 client, iq_elt, "configuration", NS_FIS_CONFIGURATION
1001 )
1002 )
974 except exceptions.CancelError: 1003 except exceptions.CancelError:
975 return 1004 return
976 except RootPathException: 1005 except RootPathException:
977 client.sendError(iq_elt, 'bad-request', "Root path can't be used") 1006 client.sendError(iq_elt, "bad-request", "Root path can't be used")
978 return 1007 return
979 try: 1008 try:
980 access_type = file_data['access'][C.ACCESS_PERM_READ]['type'] 1009 access_type = file_data["access"][C.ACCESS_PERM_READ]["type"]
981 except KeyError: 1010 except KeyError:
982 access_model = 'whitelist' 1011 access_model = "whitelist"
983 else: 1012 else:
984 access_model = 'open' if access_type == C.ACCESS_TYPE_PUBLIC else 'whitelist' 1013 access_model = "open" if access_type == C.ACCESS_TYPE_PUBLIC else "whitelist"
985 1014
986 iq_result_elt = xmlstream.toResponse(iq_elt, "result") 1015 iq_result_elt = xmlstream.toResponse(iq_elt, "result")
987 configuration_elt = iq_result_elt.addElement((NS_FIS_CONFIGURATION, 'configuration')) 1016 configuration_elt = iq_result_elt.addElement(
1017 (NS_FIS_CONFIGURATION, "configuration")
1018 )
988 form = data_form.Form(formType="form", formNamespace=NS_FIS_CONFIGURATION) 1019 form = data_form.Form(formType="form", formNamespace=NS_FIS_CONFIGURATION)
989 form.makeFields({'access_model': access_model}) 1020 form.makeFields({"access_model": access_model})
990 configuration_elt.addChild(form.toElement()) 1021 configuration_elt.addChild(form.toElement())
991 client.send(iq_result_elt) 1022 client.send(iq_result_elt)
992 1023
993 async def _set_configuration(self, client, configuration_elt, file_data): 1024 async def _set_configuration(self, client, configuration_elt, file_data):
994 form = data_form.findForm(configuration_elt, NS_FIS_CONFIGURATION) 1025 form = data_form.findForm(configuration_elt, NS_FIS_CONFIGURATION)
995 for name, value in form.items(): 1026 for name, value in form.items():
996 if name == 'access_model': 1027 if name == "access_model":
997 await self.host.memory.set_file_access_model(client, file_data, value) 1028 await self.host.memory.set_file_access_model(client, file_data, value)
998 else: 1029 else:
999 # TODO: send a IQ error? 1030 # TODO: send a IQ error?
1000 log.warning( 1031 log.warning(
1001 f"Trying to set a not implemented configuration option: {name}") 1032 f"Trying to set a not implemented configuration option: {name}"
1033 )
1002 1034
1003 def _on_component_configuration_set(self, iq_elt, client): 1035 def _on_component_configuration_set(self, iq_elt, client):
1004 iq_elt.handled = True 1036 iq_elt.handled = True
1005 defer.ensureDeferred(self.on_component_configuration_set(client, iq_elt)) 1037 defer.ensureDeferred(self.on_component_configuration_set(client, iq_elt))
1006 1038
1007 async def on_component_configuration_set(self, client, iq_elt): 1039 async def on_component_configuration_set(self, client, iq_elt):
1008 try: 1040 try:
1009 ( 1041 (from_jid, configuration_elt, path, namespace, file_data) = (
1010 from_jid, configuration_elt, path, namespace, file_data 1042 await self._parse_element(
1011 ) = await self._parse_element(client, iq_elt, "configuration", NS_FIS_CONFIGURATION) 1043 client, iq_elt, "configuration", NS_FIS_CONFIGURATION
1044 )
1045 )
1012 except exceptions.CancelError: 1046 except exceptions.CancelError:
1013 return 1047 return
1014 except RootPathException: 1048 except RootPathException:
1015 client.sendError(iq_elt, 'bad-request', "Root path can't be used") 1049 client.sendError(iq_elt, "bad-request", "Root path can't be used")
1016 return 1050 return
1017 1051
1018 from_jid_bare = from_jid.userhostJID() 1052 from_jid_bare = from_jid.userhostJID()
1019 is_owner = from_jid_bare == file_data.get('owner') 1053 is_owner = from_jid_bare == file_data.get("owner")
1020 if not is_owner: 1054 if not is_owner:
1021 log.warning( 1055 log.warning(
1022 f"{from_jid} tried to modify {path} configuration while the owner is " 1056 f"{from_jid} tried to modify {path} configuration while the owner is "
1023 f"{file_data['owner']}" 1057 f"{file_data['owner']}"
1024 ) 1058 )
1025 client.sendError(iq_elt, 'forbidden') 1059 client.sendError(iq_elt, "forbidden")
1026 return 1060 return
1027 1061
1028 await self._set_configuration(client, configuration_elt, file_data) 1062 await self._set_configuration(client, configuration_elt, file_data)
1029 1063
1030 iq_result_elt = xmlstream.toResponse(iq_elt, "result") 1064 iq_result_elt = xmlstream.toResponse(iq_elt, "result")
1033 # directory creation 1067 # directory creation
1034 1068
1035 def _create_dir(self, service_jid_s, namespace, path, configuration, profile): 1069 def _create_dir(self, service_jid_s, namespace, path, configuration, profile):
1036 client = self.host.get_client(profile) 1070 client = self.host.get_client(profile)
1037 service = jid.JID(service_jid_s) 1071 service = jid.JID(service_jid_s)
1038 return defer.ensureDeferred(self.create_dir( 1072 return defer.ensureDeferred(
1039 client, service, namespace or None, path, configuration or None)) 1073 self.create_dir(
1074 client, service, namespace or None, path, configuration or None
1075 )
1076 )
1040 1077
1041 async def create_dir( 1078 async def create_dir(
1042 self, 1079 self,
1043 client: SatXMPPEntity, 1080 client: SatXMPPEntity,
1044 service: jid.JID, 1081 service: jid.JID,
1047 configuration: Optional[Dict[str, str]], 1084 configuration: Optional[Dict[str, str]],
1048 ): 1085 ):
1049 if not path: 1086 if not path:
1050 raise ValueError(f"invalid path: {path!r}") 1087 raise ValueError(f"invalid path: {path!r}")
1051 iq_elt = client.IQ("set") 1088 iq_elt = client.IQ("set")
1052 iq_elt['to'] = service.full() 1089 iq_elt["to"] = service.full()
1053 create_dir_elt = iq_elt.addElement((NS_FIS_CREATE, "dir")) 1090 create_dir_elt = iq_elt.addElement((NS_FIS_CREATE, "dir"))
1054 if namespace: 1091 if namespace:
1055 create_dir_elt["namespace"] = namespace 1092 create_dir_elt["namespace"] = namespace
1056 create_dir_elt["path"] = path 1093 create_dir_elt["path"] = path
1057 if configuration: 1094 if configuration:
1058 configuration_elt = create_dir_elt.addElement((NS_FIS_CONFIGURATION, "configuration")) 1095 configuration_elt = create_dir_elt.addElement(
1096 (NS_FIS_CONFIGURATION, "configuration")
1097 )
1059 form = data_form.Form(formType="submit", formNamespace=NS_FIS_CONFIGURATION) 1098 form = data_form.Form(formType="submit", formNamespace=NS_FIS_CONFIGURATION)
1060 form.makeFields(configuration) 1099 form.makeFields(configuration)
1061 configuration_elt.addChild(form.toElement()) 1100 configuration_elt.addChild(form.toElement())
1062 await iq_elt.send() 1101 await iq_elt.send()
1063 1102
1066 defer.ensureDeferred(self.on_component_create_dir(client, iq_elt)) 1105 defer.ensureDeferred(self.on_component_create_dir(client, iq_elt))
1067 1106
1068 async def on_component_create_dir(self, client, iq_elt): 1107 async def on_component_create_dir(self, client, iq_elt):
1069 peer_jid, owner = client.get_owner_and_peer(iq_elt) 1108 peer_jid, owner = client.get_owner_and_peer(iq_elt)
1070 if peer_jid.host not in client._file_sharing_allowed_hosts: 1109 if peer_jid.host not in client._file_sharing_allowed_hosts:
1071 client.sendError(iq_elt, 'forbidden') 1110 client.sendError(iq_elt, "forbidden")
1072 return 1111 return
1073 create_dir_elt = next(iq_elt.elements(NS_FIS_CREATE, "dir")) 1112 create_dir_elt = next(iq_elt.elements(NS_FIS_CREATE, "dir"))
1074 namespace = create_dir_elt.getAttribute('namespace') 1113 namespace = create_dir_elt.getAttribute("namespace")
1075 path = Path("/", create_dir_elt['path']) 1114 path = Path("/", create_dir_elt["path"])
1076 if len(path.parts) < 2: 1115 if len(path.parts) < 2:
1077 client.sendError(iq_elt, 'bad-request', "Root path can't be used") 1116 client.sendError(iq_elt, "bad-request", "Root path can't be used")
1078 return 1117 return
1079 # for root directories, we check permission here 1118 # for root directories, we check permission here
1080 if len(path.parts) == 2 and owner != peer_jid.userhostJID(): 1119 if len(path.parts) == 2 and owner != peer_jid.userhostJID():
1081 log.warning( 1120 log.warning(
1082 f"{peer_jid} is trying to create a dir at {owner}'s repository:\n" 1121 f"{peer_jid} is trying to create a dir at {owner}'s repository:\n"
1083 f"path: {path}\nnamespace: {namespace!r}" 1122 f"path: {path}\nnamespace: {namespace!r}"
1084 ) 1123 )
1085 client.sendError(iq_elt, 'forbidden', "You can't create a directory there") 1124 client.sendError(iq_elt, "forbidden", "You can't create a directory there")
1086 return 1125 return
1087 # when going further into the path, the permissions will be checked by get_files 1126 # when going further into the path, the permissions will be checked by get_files
1088 files_data = await self.host.memory.get_files( 1127 files_data = await self.host.memory.get_files(
1089 client, 1128 client,
1090 peer_jid=peer_jid, 1129 peer_jid=peer_jid,
1091 path=path.parent, 1130 path=path.parent,
1092 namespace=namespace, 1131 namespace=namespace,
1093 owner=owner, 1132 owner=owner,
1094 ) 1133 )
1095 if path.name in [d['name'] for d in files_data]: 1134 if path.name in [d["name"] for d in files_data]:
1096 log.warning( 1135 log.warning(
1097 f"Conflict when trying to create a directory (from: {peer_jid} " 1136 f"Conflict when trying to create a directory (from: {peer_jid} "
1098 f"namespace: {namespace!r} path: {path!r})" 1137 f"namespace: {namespace!r} path: {path!r})"
1099 ) 1138 )
1100 client.sendError( 1139 client.sendError(
1101 iq_elt, 'conflict', "there is already a file or dir at this path") 1140 iq_elt, "conflict", "there is already a file or dir at this path"
1141 )
1102 return 1142 return
1103 1143
1104 try: 1144 try:
1105 configuration_elt = next( 1145 configuration_elt = next(
1106 create_dir_elt.elements(NS_FIS_CONFIGURATION, 'configuration')) 1146 create_dir_elt.elements(NS_FIS_CONFIGURATION, "configuration")
1147 )
1107 except StopIteration: 1148 except StopIteration:
1108 configuration_elt = None 1149 configuration_elt = None
1109 1150
1110 await self.host.memory.set_file( 1151 await self.host.memory.set_file(
1111 client, 1152 client,
1112 path.name, 1153 path.name,
1113 path=path.parent, 1154 path=path.parent,
1114 type_=C.FILE_TYPE_DIRECTORY, 1155 type_=C.FILE_TYPE_DIRECTORY,
1115 namespace=namespace, 1156 namespace=namespace,
1116 owner=owner, 1157 owner=owner,
1117 peer_jid=peer_jid 1158 peer_jid=peer_jid,
1118 ) 1159 )
1119 1160
1120 if configuration_elt is not None: 1161 if configuration_elt is not None:
1121 file_data = (await self.host.memory.get_files( 1162 file_data = (
1122 client, 1163 await self.host.memory.get_files(
1123 peer_jid=peer_jid, 1164 client,
1124 path=path.parent, 1165 peer_jid=peer_jid,
1125 name=path.name, 1166 path=path.parent,
1126 namespace=namespace, 1167 name=path.name,
1127 owner=owner, 1168 namespace=namespace,
1128 ))[0] 1169 owner=owner,
1170 )
1171 )[0]
1129 1172
1130 await self._set_configuration(client, configuration_elt, file_data) 1173 await self._set_configuration(client, configuration_elt, file_data)
1131 1174
1132 iq_result_elt = xmlstream.toResponse(iq_elt, "result") 1175 iq_result_elt = xmlstream.toResponse(iq_elt, "result")
1133 client.send(iq_result_elt) 1176 client.send(iq_result_elt)
1135 # file methods # 1178 # file methods #
1136 1179
1137 def _serialize_data(self, files_data): 1180 def _serialize_data(self, files_data):
1138 for file_data in files_data: 1181 for file_data in files_data:
1139 for key, value in file_data.items(): 1182 for key, value in file_data.items():
1140 file_data[key] = ( 1183 file_data[key] = json.dumps(value) if key in ("extra",) else str(value)
1141 json.dumps(value) if key in ("extra",) else str(value)
1142 )
1143 return files_data 1184 return files_data
1144 1185
1145 def _list_files(self, target_jid, path, extra, profile): 1186 def _list_files(self, target_jid, path, extra, profile):
1146 client = self.host.get_client(profile) 1187 client = self.host.get_client(profile)
1147 target_jid = client.jid if not target_jid else jid.JID(target_jid) 1188 target_jid = client.jid if not target_jid else jid.JID(target_jid)
1205 new_name = name + "_" + str(idx) 1246 new_name = name + "_" + str(idx)
1206 while new_name in node: 1247 while new_name in node:
1207 idx += 1 1248 idx += 1
1208 new_name = name + "_" + str(idx) 1249 new_name = name + "_" + str(idx)
1209 name = new_name 1250 name = new_name
1210 log.info(_( 1251 log.info(
1211 "A directory with this name is already shared, renamed to {new_name} " 1252 _(
1212 "[{profile}]".format( new_name=new_name, profile=client.profile))) 1253 "A directory with this name is already shared, renamed to {new_name} "
1254 "[{profile}]".format(new_name=new_name, profile=client.profile)
1255 )
1256 )
1213 1257
1214 ShareNode(name=name, parent=node, type_=node_type, access=access, path=path) 1258 ShareNode(name=name, parent=node, type_=node_type, access=access, path=path)
1215 self.host.bridge.fis_shared_path_new(path, name, client.profile) 1259 self.host.bridge.fis_shared_path_new(path, name, client.profile)
1216 return name 1260 return name
1217 1261
1234 self.host = plugin_parent.host 1278 self.host = plugin_parent.host
1235 1279
1236 def connectionInitialized(self): 1280 def connectionInitialized(self):
1237 if self.parent.is_component: 1281 if self.parent.is_component:
1238 self.xmlstream.addObserver( 1282 self.xmlstream.addObserver(
1239 IQ_FIS_REQUEST, self.plugin_parent.on_component_request, client=self.parent 1283 IQ_FIS_REQUEST,
1284 self.plugin_parent.on_component_request,
1285 client=self.parent,
1240 ) 1286 )
1241 self.xmlstream.addObserver( 1287 self.xmlstream.addObserver(
1242 IQ_FIS_AFFILIATION_GET, 1288 IQ_FIS_AFFILIATION_GET,
1243 self.plugin_parent._on_component_affiliations_get, 1289 self.plugin_parent._on_component_affiliations_get,
1244 client=self.parent 1290 client=self.parent,
1245 ) 1291 )
1246 self.xmlstream.addObserver( 1292 self.xmlstream.addObserver(
1247 IQ_FIS_AFFILIATION_SET, 1293 IQ_FIS_AFFILIATION_SET,
1248 self.plugin_parent._on_component_affiliations_set, 1294 self.plugin_parent._on_component_affiliations_set,
1249 client=self.parent 1295 client=self.parent,
1250 ) 1296 )
1251 self.xmlstream.addObserver( 1297 self.xmlstream.addObserver(
1252 IQ_FIS_CONFIGURATION_GET, 1298 IQ_FIS_CONFIGURATION_GET,
1253 self.plugin_parent._on_component_configuration_get, 1299 self.plugin_parent._on_component_configuration_get,
1254 client=self.parent 1300 client=self.parent,
1255 ) 1301 )
1256 self.xmlstream.addObserver( 1302 self.xmlstream.addObserver(
1257 IQ_FIS_CONFIGURATION_SET, 1303 IQ_FIS_CONFIGURATION_SET,
1258 self.plugin_parent._on_component_configuration_set, 1304 self.plugin_parent._on_component_configuration_set,
1259 client=self.parent 1305 client=self.parent,
1260 ) 1306 )
1261 self.xmlstream.addObserver( 1307 self.xmlstream.addObserver(
1262 IQ_FIS_CREATE_DIR, 1308 IQ_FIS_CREATE_DIR,
1263 self.plugin_parent._on_component_create_dir, 1309 self.plugin_parent._on_component_create_dir,
1264 client=self.parent 1310 client=self.parent,
1265 ) 1311 )
1266 else: 1312 else:
1267 self.xmlstream.addObserver( 1313 self.xmlstream.addObserver(
1268 IQ_FIS_REQUEST, self.plugin_parent.on_request, client=self.parent 1314 IQ_FIS_REQUEST, self.plugin_parent.on_request, client=self.parent
1269 ) 1315 )