def __init__(self, jrd): """Initalise WebFingerJRD object with jrd. args: jrd - the JRD of the WebFinger response. """ if not isinstance(jrd, Mapping): raise WebFingerJRDError("JRD must be a Mapping") self.jrd = jrd try: self.subject = jrd["subject"] except Exception as e: raise WebFingerJRDError("subject is required in JRD") from e self.aliases = jrd.get("aliases", []) self.properties = jrd.get("properties", {}) self.links = [] for link in jrd.get("links", []): self.links.append(WebFingerLink(**link)) # Create rels list self.link_rels = OrderedDict() for link in self.links: rel = REL_NAMES.get(link.rel, link.rel) if rel not in self.link_rels: rel_list = self.link_rels[rel] = list() else: rel_list = self.link_rels[rel] rel_list.append(link)
def add_link(self, rel, *, type=None, href=None, titles=None, properties=None, misc=dict(), **kwargs): """Add a link to the JRD. args: rel - the relation type of the link type - MIME type the dereferencing link href - target URI of the link properties - mapping (both keys and values must be strings) containing URI's and values misc - a mapping of other items to add to the link kwargs - other items to add to the link """ if "links" not in self.jrd: self.jrd["links"] = [] if rel in RELS: # Convert rel into URI rel = RELS[rel] if not is_uri(rel): raise WebFingerJRDError("rel must be a valid URI") args = {"rel": rel} if type: args["type"] = type if href: args["href"] = href if titles: args["titles"] = titles if properties: args["properties"] = properties if not isinstance(misc, Mapping): raise WebFingerJRDError("misc must be a mapping") args.update(misc) args.update(kwargs) self.links.append(WebFingerLink(**args)) self.jrd["links"].append(args)
def build(cls, subject): """Create a WebFingerJRD object based around the given subject. args: subject - subject of the JRD """ if "@" not in subject: raise WebFingerJRDError("subject must be in user@host format") if not isinstance(subject, str): raise WebFingerJRDError("subject must be a string") if not subject.startswith("acct:"): subject = "acct:" + subject return cls({"subject": subject})
def add_alias(self, alias): """Add an alias to the JRD. args: alias - the alias to add to the JRD. Must be a string and a valid URI. """ if "aliases" not in self.jrd: self.jrd["aliases"] = [] if not isinstance(alias, str): raise WebFingerJRDError("alias must be a string") if not is_uri(alias): raise WebFingerJRDError("alias must be a URI") self.aliases.append(alias) self.jrd["aliases"].append(alias)
def from_json(cls, text): """Initalise JRD with json plaintext. args: text - json text to parse. Must be a string. """ try: jrd = json.loads(text) except Exception as e: raise WebFingerJRDError("error parsing JRD") from e return cls(jrd)
def add_property(self, uri, value=None): """Add a property to the JRD. args: uri - uri for the property value - value to assign for the property; must be either a string or None """ if "properties" not in self.jrd: self.jrd["properties"] = {} if not isinstance(uri, str): raise WebFingerJRDError("uri must be a string") if not is_uri(uri): raise WebFingerJRDError("uri must be a URI") if not isinstance(value, (str, type(None))): raise WebFingerJRDError("value for uri must be a string or None") self.properties[uri] = value self.jrd["properties"][uri] = value
def parse_properties(node): ret = {} properties = node.findall("XRD:Property", XMLNSMAP) if not properties: return ret for property in properties: if "type" not in property.attrib: raise WebFingerJRDError("type is required with property") key = property.attrib["type"] has_nil = property.attrib.get("xsi:nil", "").lower() if has_nil and has_nil == "true": value = None else: value = property.text ret[key] = value return ret
def __init__(self, rel, *, type=None, href=None, titles=None, properties=None, **kwargs): """Initalise the WebFingerLink object. args: rel - relation of the link; this is required keyword arguments: type - expected MIME type of the link href - URI for the link titles - a mapping of titles of the object to languages properties - a mapping of given properties of the subject All other arguments are set as attrs on this object. """ self._link = {"rel": rel} if type is not None: if not isinstance(type, str): raise WebFingerJRDError("type must be a string") self._link["type"] = type if href is not None: if not isinstance(href, str): raise WebFingerJRDError("href must be a string") if not is_uri(href): raise WebFingerJRDError("href must be a valid URI") self._link["href"] = href if titles is not None: if not isinstance(titles, Mapping): raise WebFingerJRDError("titles must be a mapping") for k, v in titles.items(): if not isinstance(k, str): raise WebFingerJRDError("title must be a string") if not isinstance(v, str): raise WebFingerJRDError("title language must be a string") self._link["titles"] = titles if properties is not None: if not isinstance(properties, Mapping): raise WebFingerJRDError("properties must be a mapping") for k, v in properties.items(): if not is_uri(k): raise WebFingerJRDError("properties keys must be URI's") if not isinstance(v, str) or v is not None: raise WebFingerJRDError( "properties values must be strings, or None", v) self._link["properties"] = properties for k, v in kwargs.items(): # No validation performed on other items self._link[k] = v