Mercurial > libervia-backend
view libervia/frontends/tools/jid.py @ 4213:716dd791be46
tests (unit): fix tests
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 23 Feb 2024 15:42:02 +0100 |
parents | 26b7ed2817da |
children |
line wrap: on
line source
#!/usr/bin/env python3 # Libervia XMPP # Copyright (C) 2009-2023 Jérôme Poisson (goffi@goffi.org) # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from typing import Optional, Tuple class JID(str): """This class helps manage JID (<local>@<domain>/<resource>)""" def __new__(cls, jid_str: str) -> "JID": return str.__new__(cls, cls._normalize(jid_str)) def __init__(self, jid_str: str): self._node, self._domain, self._resource = self._parse() @staticmethod def _normalize(jid_str: str) -> str: """Naive normalization before instantiating and parsing the JID""" if not jid_str: return jid_str tokens = jid_str.split("/") tokens[0] = tokens[0].lower() # force node and domain to lower-case return "/".join(tokens) def _parse(self) -> Tuple[Optional[str], str, Optional[str]]: """Find node, domain, and resource from JID""" node_end = self.find("@") if node_end < 0: node_end = 0 domain_end = self.find("/") if domain_end == 0: raise ValueError("a jid can't start with '/'") if domain_end == -1: domain_end = len(self) node = self[:node_end] or None domain = self[(node_end + 1) if node_end else 0 : domain_end] resource = self[domain_end + 1 :] or None return node, domain, resource @property def node(self) -> Optional[str]: return self._node @property def local(self) -> Optional[str]: return self._node @property def domain(self) -> str: return self._domain @property def resource(self) -> Optional[str]: return self._resource @property def bare(self) -> "JID": if not self.node: return JID(self.domain) return JID(f"{self.node}@{self.domain}") def change_resource(self, resource: str) -> "JID": """Build a new JID with the same node and domain but a different resource. @param resource: The new resource for the JID. @return: A new JID instance with the updated resource. """ return JID(f"{self.bare}/{resource}") def is_valid(self) -> bool: """ @return: True if the JID is XMPP compliant """ # Simple check for domain part if not self.domain or self.domain.startswith(".") or self.domain.endswith("."): return False if ".." in self.domain: return False return True def new_resource(entity: JID, resource: str) -> JID: """Build a new JID from the given entity and resource. @param entity: original JID @param resource: new resource @return: a new JID instance """ return entity.change_resource(resource)