From 511b6ecb108d9a00340f1e58b849c3fcdb4536c9 Mon Sep 17 00:00:00 2001 From: Mikael Frykholm <mikael@frykholm.com> Date: Fri, 1 Apr 2016 05:52:41 +0200 Subject: [PATCH] Some xml fixes, added rd library --- friends/rd/__init__.py | 6 + .../rd/__pycache__/__init__.cpython-35.pyc | Bin 0 -> 326 bytes friends/rd/__pycache__/core.cpython-35.pyc | Bin 0 -> 12786 bytes friends/rd/__pycache__/jrd.cpython-35.pyc | Bin 0 -> 4036 bytes friends/rd/core.py | 390 ++++++++++++++++++ friends/rd/jrd.py | 146 +++++++ friends/rd/xrd.py | 163 ++++++++ friends/server.py | 3 + friends/static/mikael.jpg | Bin 0 -> 23571 bytes friends/templates/feed.xml | 3 +- 10 files changed, 710 insertions(+), 1 deletion(-) create mode 100644 friends/rd/__init__.py create mode 100644 friends/rd/__pycache__/__init__.cpython-35.pyc create mode 100644 friends/rd/__pycache__/core.cpython-35.pyc create mode 100644 friends/rd/__pycache__/jrd.cpython-35.pyc create mode 100644 friends/rd/core.py create mode 100644 friends/rd/jrd.py create mode 100755 friends/rd/xrd.py create mode 100644 friends/static/mikael.jpg diff --git a/friends/rd/__init__.py b/friends/rd/__init__.py new file mode 100644 index 0000000..0386a2d --- /dev/null +++ b/friends/rd/__init__.py @@ -0,0 +1,6 @@ +from rd.core import * + +__author__ = "Jeremy Carbaugh (jcarbaugh@gmail.com)" +__version__ = "0.1" +__copyright__ = "Copyright (c) 2012 Jeremy Carbaugh" +__license__ = "BSD" diff --git a/friends/rd/__pycache__/__init__.cpython-35.pyc b/friends/rd/__pycache__/__init__.cpython-35.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b27d3fdbb7fe1cc1201c67aaaa02a2389126280 GIT binary patch literal 326 zcmZ8by-ve05I!gAkAku?M@XQCA#OV(R8b}dmLdi(r(m1J5XY61ASKVj3-pyDHYQ#H z7R+A<?&rJjba$WbFp9#L=a1VR0KB@~o9EcdWqsm6xFAph+z1aC0pSDlKm@>i5F=m# zh%s!E$(!4Sgbd`gKfaPy>MmYq_AYDlBAz|)U%JY5rplBXo%H@ZUGzt5v+b<Pizc4& zBwo%J%lO|p^Dj1+*U5-YtZ<iB4k2RJHifZ>>;Ume+FF^)H4!5J)BBl~ip#2&h&!-> z`|umyDJ_haRIA5KmbA8<-diOrQSYl26j4>GK}@&ZFg?>ow52>JPNSYW2)!}+@=qz; BS^59~ literal 0 HcmV?d00001 diff --git a/friends/rd/__pycache__/core.cpython-35.pyc b/friends/rd/__pycache__/core.cpython-35.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e417a5516ee60c94b3ef5a4608d2edbd925cc229 GIT binary patch literal 12786 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 BqHF*F literal 0 HcmV?d00001 diff --git a/friends/rd/__pycache__/jrd.cpython-35.pyc b/friends/rd/__pycache__/jrd.cpython-35.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3421e215bde702663d2dea3e10eaaffc293b859a GIT binary patch literal 4036 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 literal 0 HcmV?d00001 diff --git a/friends/rd/core.py b/friends/rd/core.py new file mode 100644 index 0000000..b017434 --- /dev/null +++ b/friends/rd/core.py @@ -0,0 +1,390 @@ +import datetime +import logging + +RFC6415_TYPE = 'application/xrd+xml' +RFC7033_TYPE = 'application/jrd+json' + +JRD_TYPES = ('application/jrd+json', 'application/xrd+json', 'application/json', 'text/json') +XRD_TYPES = ('application/xrd+xml', 'text/xml') + +KNOWN_RELS = { + 'activity_streams': 'http://activitystrea.ms/spec/1.0', + 'app': ('http://apinamespace.org/atom', 'application/atomsvc+xml'), + 'avatar': 'http://webfinger.net/rel/avatar', + 'foaf': ('describedby', 'application/rdf+xml'), + 'hcard': 'http://microformats.org/profile/hcard', + 'oauth_access_token': 'http://apinamespace.org/oauth/access_token', + 'oauth_authorize': 'http://apinamespace.org/oauth/authorize', + 'oauth_request_token': 'http://apinamespace.org/oauth/request_token', + 'openid': 'http://specs.openid.net/auth/2.0/provider', + 'opensocial': 'http://ns.opensocial.org/2008/opensocial/activitystreams', + 'portable_contacts': 'http://portablecontacts.net/spec/1.0', + 'profile': 'http://webfinger.net/rel/profile-page', + 'updates_from': 'http://schemas.google.com/g/2010#updates-from', + 'ostatus_sub': 'http://ostatus.org/schema/1.0/subscribe', + 'salmon_endpoint': 'salmon', + 'salmon_key': 'magic-public-key', + 'webfist': 'http://webfist.org/spec/rel', + 'xfn': 'http://gmpg.org/xfn/11', + + 'jrd': ('lrdd', 'application/json'), + 'webfinger': ('lrdd', 'application/jrd+json'), + 'xrd': ('lrdd', 'application/xrd+xml'), +} + +logger = logging.getLogger("rd") + + +def _is_str(s): + try: + return isinstance(s, str) + except NameError: + return isinstance(s, str) + + +def loads(content, content_type): + + from rd import jrd, xrd + + content_type = content_type.split(";")[0] + + if content_type in JRD_TYPES: + logger.debug("loads() loading JRD") + return jrd.loads(content) + + elif content_type in XRD_TYPES: + logger.debug("loads() loading XRD") + return xrd.loads(content) + + raise TypeError('Unknown content type') + +# +# helper functions for host parsing and discovery +# + +def parse_uri_components(resource, default_scheme='https'): + hostname = None + scheme = default_scheme + + from urllib.parse import urlparse + + parts = urlparse(resource) + if parts.scheme and parts.netloc: + scheme = parts.scheme + ''' FIXME: if we have https://user@some.example/ we end up with parts.netloc='user@some.example' here. ''' + hostname = parts.netloc + path = parts.path + + elif parts.scheme == 'acct' or (not parts.scheme and '@' in parts.path): + ''' acct: means we expect WebFinger to work, and RFC7033 requires https, so host-meta should support it too. ''' + scheme = 'https' + + ''' We should just have user@site.example here, but if it instead + is user@site.example/whatever/else we have to split it later + on the first slash character, '/'. + ''' + hostname = parts.path.split('@')[-1] + path = None + + ''' In case we have hostname=='site.example/whatever/else' we do the split + on the first slash, giving us 'site.example' and 'whatever/else'. + ''' + if '/' in hostname: + (hostname, path) = hostname.split('/', maxsplit=1) + ''' Normalize path so it always starts with /, which is the behaviour of urlparse too. ''' + path = '/' + path + + else: + if not parts.path: + raise ValueError('No hostname could be deduced from arguments.') + + elif '/' in parts.path: + (hostname, path) = parts.path.split('/', maxsplit=1) + ''' Normalize path so it always starts with /, which is the behaviour of urlparse too. ''' + path = '/' + path + else: + hostname = parts.path + path = None + + return (scheme, hostname, path) + +# +# special XRD types +# + +class Attribute(object): + + def __init__(self, name, value): + self.name = name + self.value = value + + def __cmp__(self, other): + return cmp(str(self), str(other)) + + def __eq__(self, other): + return str(self) == other + + def __str__(self): + return "%s=%s" % (self.name, self.value) + + +class Element(object): + + def __init__(self, name, value, attrs=None): + self.name = name + self.value = value + self.attrs = attrs or {} + + +class Title(object): + + def __init__(self, value, lang=None): + self.value = value + self.lang = lang + + def __cmp__(self, other): + return cmp(str(self), str(other)) + + def __eq__(self, other): + return str(self) == str(other) + + def __str__(self): + if self.lang: + return "%s:%s" % (self.lang, self.value) + return self.value + + +class Property(object): + + def __init__(self, type_, value=None): + self.type = type_ + self.value = value + + def __cmp__(self, other): + return cmp(str(self), str(other)) + + def __eq__(self, other): + return str(self) == other + + def __str__(self): + if self.value: + return "%s:%s" % (self.type, self.value) + return self.type + + +# +# special list types +# + +class ListLikeObject(list): + + def __setitem__(self, key, value): + value = self.item(value) + super(ListLikeObject, self).__setitem__(key, value) + + def append(self, value): + value = self.item(value) + super(ListLikeObject, self).append(value) + + def extend(self, values): + values = (self.item(value) for value in values) + super(ListLikeObject, self).extend(values) + + +class AttributeList(ListLikeObject): + + def __call__(self, name): + for attr in self: + if attr.name == name: + yield attr + + def item(self, value): + if isinstance(value, (list, tuple)): + return Attribute(*value) + elif not isinstance(value, Attribute): + raise ValueError('value must be an instance of Attribute') + return value + + +class ElementList(ListLikeObject): + + def item(self, value): + if not isinstance(value, Element): + raise ValueError('value must be an instance of Type') + return value + + +class TitleList(ListLikeObject): + + def item(self, value): + if _is_str(value): + return Title(value) + elif isinstance(value, (list, tuple)): + return Title(*value) + elif not isinstance(value, Title): + raise ValueError('value must be an instance of Title') + return value + + +class LinkList(ListLikeObject): + + def __call__(self, rel): + for link in self: + if link.rel == rel: + yield link + + def item(self, value): + if not isinstance(value, Link): + raise ValueError('value must be an instance of Link') + return value + + +class PropertyList(ListLikeObject): + + def __call__(self, type_): + for prop in self: + if prop.type == type_: + yield prop + + def item(self, value): + if _is_str(value): + return Property(value) + elif isinstance(value, (tuple, list)): + return Property(*value) + elif not isinstance(value, Property): + raise ValueError('value must be an instance of Property') + return value + + +# +# Link object +# + +class Link(object): + + def __init__(self, rel=None, type=None, href=None, template=None): + self.rel = rel + self.type = type + self.href = href + self.template = template + self._titles = TitleList() + self._properties = PropertyList() + + def get_titles(self): + return self._titles + titles = property(get_titles) + + def get_properties(self): + return self._properties + properties = property(get_properties) + + def apply_template(self, uri): + + from urllib.parse import quote + + if not self.template: + raise TypeError('This is not a template Link') + return self.template.replace('{uri}', quote(uri, safe='')) + + def __str__(self): + + from cgi import escape + + attrs = '' + for prop in ['rel', 'type', 'href', 'template']: + val = getattr(self, prop) + if val: + attrs += ' {!s}="{!s}"'.format(escape(prop), escape(val)) + + return '<Link{!s}/>'.format(attrs) + + +# +# main RD class +# + +class RD(object): + + def __init__(self, xml_id=None, subject=None): + + self.xml_id = xml_id + self.subject = subject + self._expires = None + self._aliases = [] + self._properties = PropertyList() + self._links = LinkList() + self._signatures = [] + + self._attributes = AttributeList() + self._elements = ElementList() + + # ser/deser methods + + def to_json(self): + from rd import jrd + return jrd.dumps(self) + + def to_xml(self): + from rd import xrd + return xrd.dumps(self) + + # helper methods + + def find_link(self, rels, attr=None, mimetype=None): + if not isinstance(rels, (list, tuple)): + rels = (rels,) + for link in self.links: + if link.rel in rels: + if mimetype and link.type != mimetype: + continue + if attr: + return getattr(link, attr, None) + return link + + def __getattr__(self, name, attr=None): + if name in KNOWN_RELS: + try: + ''' If we have a specific mimetype for this rel value ''' + rel, mimetype = KNOWN_RELS[name] + except ValueError: + rel = KNOWN_RELS[name] + mimetype = None + return self.find_link(rel, attr=attr, mimetype=mimetype) + raise AttributeError(name) + + # custom elements and attributes + + def get_elements(self): + return self._elements + elements = property(get_elements) + + @property + def attributes(self): + return self._attributes + + # defined elements and attributes + + def get_expires(self): + return self._expires + + def set_expires(self, expires): + if not isinstance(expires, datetime.datetime): + raise ValueError('expires must be a datetime object') + self._expires = expires + expires = property(get_expires, set_expires) + + def get_aliases(self): + return self._aliases + aliases = property(get_aliases) + + def get_properties(self): + return self._properties + properties = property(get_properties) + + def get_links(self): + return self._links + links = property(get_links) + + def get_signatures(self): + return self._signatures + signatures = property(get_links) diff --git a/friends/rd/jrd.py b/friends/rd/jrd.py new file mode 100644 index 0000000..4dda5b5 --- /dev/null +++ b/friends/rd/jrd.py @@ -0,0 +1,146 @@ + +import json +import isodate + +from rd.core import RD, Attribute, Element, Link, Property, Title + + +def _clean_dict(d): + for key in list(d.keys()): + if not d[key]: + del d[key] + + +def loads(content): + + def expires_handler(key, val, obj): + obj.expires = isodate.parse_datetime(val) + + def subject_handler(key, val, obj): + obj.subject = val + + def aliases_handler(key, val, obj): + for alias in val: + obj.aliases.append(alias) + + def properties_handler(key, val, obj): + for ptype, pvalue in list(val.items()): + obj.properties.append(Property(ptype, pvalue)) + + def titles_handler(key, val, obj): + for tlang, tvalue in list(val.items()): + if tlang == 'default': + tlang = None + obj.titles.append(Title(tvalue, tlang)) + + def links_handler(key, val, obj): + for link in val: + l = Link() + l.rel = link.get('rel', None) + l.type = link.get('type', None) + l.href = link.get('href', None) + l.template = link.get('template', None) + if 'titles' in link: + titles_handler('title', link['titles'], l) + if 'properties' in link: + properties_handler('property', link['properties'], l) + obj.links.append(l) + + def namespace_handler(key, val, obj): + for namespace in val: + ns = list(namespace.keys())[0] + ns_uri = list(namespace.values())[0] + obj.attributes.append(Attribute("xmlns:%s" % ns, ns_uri)) + + handlers = { + 'expires': expires_handler, + 'subject': subject_handler, + 'aliases': aliases_handler, + 'properties': properties_handler, + 'links': links_handler, + 'titles': titles_handler, + 'namespace': namespace_handler, + } + + def unknown_handler(key, val, obj): + if ':' in key: + (ns, name) = key.split(':') + key = "%s:%s" % (ns, name.capitalize()) + obj.elements.append(Element(key, val)) + + doc = json.loads(content) + + rd = RD() + + for key, value in list(doc.items()): + handler = handlers.get(key, unknown_handler) + handler(key, value, rd) + + return rd + + +def dumps(xrd): + + doc = { + "aliases": [], + "links": [], + "namespace": [], + "properties": {}, + "titles": [], + } + + #list_keys = doc.keys() + + for attr in xrd.attributes: + if attr.name.startswith("xmlns:"): + ns = attr.name.split(":")[1] + doc['namespace'].append({ns: attr.value}) + + if xrd.expires: + doc['expires'] = xrd.expires.isoformat() + + if xrd.subject: + doc['subject'] = xrd.subject + + for alias in xrd.aliases: + doc['aliases'].append(alias) + + for prop in xrd.properties: + doc['properties'][prop.type] = prop.value + + for link in xrd.links: + + link_doc = { + 'titles': {}, + 'properties': {}, + } + + if link.rel: + link_doc['rel'] = link.rel + + if link.type: + link_doc['type'] = link.type + + if link.href: + link_doc['href'] = link.href + + if link.template: + link_doc['template'] = link.template + + for prop in link.properties: + link_doc['properties'][prop.type] = prop.value + + for title in link.titles: + lang = title.lang or "default" + link_doc['titles'][lang] = title.value + + _clean_dict(link_doc) + + doc['links'].append(link_doc) + + for elem in xrd.elements: + doc[elem.name.lower()] = elem.value + + _clean_dict(doc) + + return json.dumps(doc) diff --git a/friends/rd/xrd.py b/friends/rd/xrd.py new file mode 100755 index 0000000..afc1247 --- /dev/null +++ b/friends/rd/xrd.py @@ -0,0 +1,163 @@ + +from xml.dom.minidom import getDOMImplementation, parseString, Node + +from rd.core import RD, Element, Link, Property, Title + +XRD_NAMESPACE = "http://docs.oasis-open.org/ns/xri/xrd-1.0" + + +def _get_text(root): + text = '' + for node in root.childNodes: + if node.nodeType == Node.TEXT_NODE and node.nodeValue: + text += node.nodeValue + else: + text += _get_text(node) + return text.strip() or None + + +def loads(content): + + import isodate + + def expires_handler(node, obj): + obj.expires = isodate.parse_datetime(_get_text(node)) + + def subject_handler(node, obj): + obj.subject = _get_text(node) + + def alias_handler(node, obj): + obj.aliases.append(_get_text(node)) + + def property_handler(node, obj): + obj.properties.append(Property(node.getAttribute('type'), _get_text(node))) + + def title_handler(node, obj): + obj.titles.append(Title(_get_text(node), node.getAttribute('xml:lang'))) + + def link_handler(node, obj): + l = Link() + l.rel = node.getAttribute('rel') + l.type = node.getAttribute('type') + l.href = node.getAttribute('href') + l.template = node.getAttribute('template') + obj.links.append(l) + + handlers = { + 'Expires': expires_handler, + 'Subject': subject_handler, + 'Alias': alias_handler, + 'Property': property_handler, + 'Link': link_handler, + 'Title': title_handler, + } + + def unknown_handler(node, obj): + obj.elements.append(Element( + name=node.tagName, + value=_get_text(node), + )) + + def handle_node(node, obj): + handler = handlers.get(node.nodeName, unknown_handler) + if handler and node.nodeType == node.ELEMENT_NODE: + handler(node, obj) + + doc = parseString(content) + root = doc.documentElement + + rd = RD(root.getAttribute('xml:id')) + + for name, value in list(root.attributes.items()): + if name != 'xml:id': + rd.attributes.append((name, value)) + + for node in root.childNodes: + handle_node(node, rd) + if node.nodeName == 'Link': + link = rd.links[-1] + for child in node.childNodes: + handle_node(child, link) + + return rd + + +def dumps(xrd): + + doc = getDOMImplementation().createDocument(XRD_NAMESPACE, "XRD", None) + root = doc.documentElement + root.setAttribute('xmlns', XRD_NAMESPACE) + + if xrd.xml_id: + root.setAttribute('xml:id', xrd.xml_id) + + for attr in xrd.attributes: + root.setAttribute(attr.name, attr.value) + + if xrd.expires: + node = doc.createElement('Expires') + node.appendChild(doc.createTextNode(xrd.expires.isoformat())) + root.appendChild(node) + + if xrd.subject: + node = doc.createElement('Subject') + node.appendChild(doc.createTextNode(xrd.subject)) + root.appendChild(node) + + for alias in xrd.aliases: + node = doc.createElement('Alias') + node.appendChild(doc.createTextNode(alias)) + root.appendChild(node) + + for prop in xrd.properties: + node = doc.createElement('Property') + node.setAttribute('type', prop.type) + if prop.value: + node.appendChild(doc.createTextNode(str(prop.value))) + else: + node.setAttribute('xsi:nil', 'true') + root.appendChild(node) + + for element in xrd.elements: + node = doc.createElement(element.name) + node.appendChild(doc.createTextNode(element.value)) + root.appendChild(node) + + for link in xrd.links: + + if link.href and link.template: + raise ValueError('only one of href or template attributes may be specified') + + link_node = doc.createElement('Link') + + if link.rel: + link_node.setAttribute('rel', link.rel) + + if link.type: + link_node.setAttribute('type', link.type) + + if link.href: + link_node.setAttribute('href', link.href) + + if link.template: + link_node.setAttribute('template', link.template) + + for title in link.titles: + node = doc.createElement('Title') + node.appendChild(doc.createTextNode(str(title))) + if title.lang: + node.setAttribute('xml:lang', title.lang) + link_node.appendChild(node) + + for prop in link.properties: + node = doc.createElement('Property') + node.setAttribute('type', prop.type) + if prop.value: + node.appendChild(doc.createTextNode(str(prop.value))) + else: + node.setAttribute('xsi:nil', 'true') + link_node.appendChild(node) + + root.appendChild(link_node) + + return doc diff --git a/friends/server.py b/friends/server.py index ca64779..750ddc8 100644 --- a/friends/server.py +++ b/friends/server.py @@ -30,6 +30,7 @@ class PushHandler(tornado.web.RequestHandler): hub_lease_seconds = self.get_argument('hub.lease_seconds','') hub_secret = self.get_argument('hub.sercret','') hub_verify_token = self.get_argument('hub.verify_token','') + print(self.request.body) if hub_mode == 'unsubscribe': pass #FIXME path = hub_topic.split(self.settings['domain'])[1] @@ -39,6 +40,8 @@ class PushHandler(tornado.web.RequestHandler): db.execute("INSERT into subscriptions (userid, expires, callback, verified) values (?,?,?,?)",(row['id'],datetime.datetime.now(),hub_callback,False)) db.commit() self.set_status(202) + #TODO add GET callback with the same data we got + #TODO store secret, add it to outgoing feeds with hmac class XrdHandler(tornado.web.RequestHandler): def get(self): self.render("templates/xrd.xml", hostname="ronin.frykholm.com", url=self.settings['domain']) diff --git a/friends/static/mikael.jpg b/friends/static/mikael.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ace1db236d78d03733bb0fe10a04e03264496d8a GIT binary patch literal 23571 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 literal 0 HcmV?d00001 diff --git a/friends/templates/feed.xml b/friends/templates/feed.xml index 4308d1e..320eb65 100644 --- a/friends/templates/feed.xml +++ b/friends/templates/feed.xml @@ -1,9 +1,10 @@ <?xml version="1.0" encoding="UTF-8"?> -<feed xmlns:activity='http://activitystrea.ms/spec/1.0/' xmlns='http://www.w3.org/2005/Atom'><link rel='hub' href='{{hub_url}}'/><link rel='self' href='{{user}}'/> +<feed xmlns:activity='http://activitystrea.ms/spec/1.0/' xmlns='http://www.w3.org/2005/Atom' xmlns:poco="http://portablecontacts.net/spec/1.0"><link rel='hub' href='{{hub_url}}'/><link rel='self' href='{{feed_url}}' type="application/atom+xml"/> <author> <uri>{{feed_url}}</uri> <name>{{user}}</name> <object-type xmlns='http://activitystrea.ms/spec/1.0/'>http://activitystrea.ms/schema/1.0/person</object-type> + <poco:preferredUsername>{{user}}</poco:preferredUsername> </author> <title>{{user}}'s tidslinje</title> <id>{{feed_url}}</id> -- 2.39.5