def post(self): user = users.get_current_user() newlocalname = self.request.get('newlocalname') oldlocalname = self.request.get('oldlocalname') newnickname = self.request.get('newnickname') newpublickey = self.request.get('newpublickey') old_profile_url = make_profile_url(oldlocalname, self.request.host) new_profile_url = make_profile_url(newlocalname, self.request.host) profileResults = db.GqlQuery( "SELECT * FROM Profile WHERE profile_url = :old_profile_url", old_profile_url=old_profile_url).fetch(1) if len(profileResults) == 0: # Doesn't exist, so create it: logging.info("Creating %s %s %s" % (newlocalname, user, newnickname)) p = prepare_profile_for_user(user, self.request.host) else: # Already exists, update if ACL checks out: logging.info("Updating %s with %s %s %s" % (oldlocalname, newlocalname, user, newnickname)) p = profileResults[0] if p.local_owner != user: self.response.set_status(403) #Forbidden! return p.profile_url = new_profile_url p.display_name = newnickname p.public_key = newpublickey p.put() # Create or update existing self.redirect(new_profile_url)
def decorate_comment(comment): comment.decorated_content = comment.content comment.author_uri = comment.author_profile.profile_url if not comment.author_uri: comment.author_uri = 'about:blank' logging.info("Author_uri = %s" % comment.author_uri) comment.author_display_name = comment.author_profile.display_name client = webfinger.Client() for mention in comment.mentions: replacer = re.compile(mention) # relying on memcache to make this not painful. Should probably store this with the original # mention information on write. (TODO) try: # use http://webfinger.net/rel/profile-page rel link from webfinger to get link to profile page. xrd_list = client.lookup(mention) profile_uris = ['about:blank'] for item in xrd_list: profile_uris = [ link.href for link in item.links if link.rel == 'http://webfinger.net/rel/profile-page' ] linkedMention = "<a href='%s' title='Link to profile for %s'>%s</a>" % ( profile_uris[0], mention, mention) comment.decorated_content = replacer.sub(linkedMention, comment.decorated_content) except: pass #TODO: log? return comment
def post(self): user = users.get_current_user() newlocalname = self.request.get('newlocalname') oldlocalname = self.request.get('oldlocalname') newnickname = self.request.get('newnickname') newpublickey = self.request.get('newpublickey') old_profile_url = make_profile_url(oldlocalname, self.request.host) new_profile_url = make_profile_url(newlocalname, self.request.host) profileResults = db.GqlQuery("SELECT * FROM Profile WHERE profile_url = :old_profile_url", old_profile_url=old_profile_url).fetch(1) if len(profileResults) == 0: # Doesn't exist, so create it: logging.info("Creating %s %s %s" % (newlocalname, user, newnickname) ) p = prepare_profile_for_user(user, self.request.host) else: # Already exists, update if ACL checks out: logging.info("Updating %s with %s %s %s" % (oldlocalname, newlocalname, user, newnickname) ) p = profileResults[0] if p.local_owner != user: self.response.set_status(403) #Forbidden! return p.profile_url = new_profile_url p.display_name = newnickname p.public_key = newpublickey p.put() # Create or update existing self.redirect(new_profile_url)
def decorate_comment(comment): comment.decorated_content = comment.content comment.author_uri = comment.author_profile.profile_url if not comment.author_uri: comment.author_uri = 'about:blank' logging.info("Author_uri = %s" % comment.author_uri) comment.author_display_name = comment.author_profile.display_name client = webfinger.Client() for mention in comment.mentions: replacer = re.compile(mention) # relying on memcache to make this not painful. Should probably store this with the original # mention information on write. (TODO) try: # use http://webfinger.net/rel/profile-page rel link from webfinger to get link to profile page. xrd_list = client.lookup(mention) profile_uris = ['about:blank'] for item in xrd_list: profile_uris = [link.href for link in item.links if link.rel == 'http://webfinger.net/rel/profile-page'] linkedMention = "<a href='%s' title='Link to profile for %s'>%s</a>" % (profile_uris[0], mention, mention) comment.decorated_content = replacer.sub(linkedMention, comment.decorated_content) except: pass #TODO: log? return comment
def post(self): comment_text = self.request.get('comment-text') comment_mentions = extract_mentions(comment_text) comment_text = self.request.get('comment-text') client = webfinger.Client() profile_uris = ['about:blank'] try: xrd_list = client.lookup(users.get_current_user().email()) for item in xrd_list: profile_uris = [ link.href for link in item.links if link.rel == 'http://webfinger.net/rel/profile-page' ] except: pass #TODO: log? user = users.get_current_user() p = profile_handler.ensure_profile(user, self.request.host) assert p logging.info('saw mentions: %s' % comment_mentions) c = datamodel.Comment(author_profile=p, posted_at=datetime.datetime.now(), content=comment_text, mentions=comment_mentions, parent_uri=self.request.url) c.put() do_salmon_slaps(comment_mentions, c) self.response.out.write("thanks") self.redirect(self.request.url)
def post(self): comment_text = self.request.get('comment-text') comment_mentions = extract_mentions(comment_text) comment_text = self.request.get('comment-text') client = webfinger.Client() profile_uris = ['about:blank'] try: xrd_list = client.lookup(users.get_current_user().email()) for item in xrd_list: profile_uris = [link.href for link in item.links if link.rel == 'http://webfinger.net/rel/profile-page'] except: pass #TODO: log? user = users.get_current_user() p = profile_handler.ensure_profile(user, self.request.host) assert p logging.info('saw mentions: %s' % comment_mentions) c = datamodel.Comment( author_profile=p, posted_at=datetime.datetime.now(), content=comment_text, mentions=comment_mentions, parent_uri=self.request.url) c.put() do_salmon_slaps(comment_mentions, c) self.response.out.write("thanks"); self.redirect(self.request.url);
def to_atom_entry(c): ATOM_ENTRY_TMPL = """<?xml version='1.0' encoding='UTF-8'?> <entry xmlns='http://www.w3.org/2005/Atom'> <id>tag:example.com,2009:%s</id> <author><name>%s</name><uri>%s</uri></author> <content>%s</content> <title>Salmon slap</title> <updated>%s</updated> </entry>""" logging.info('turning into atom entry: %s' % c) args = (c.key(), c.author_profile.display_name, c.author_profile.profile_url, c.content, c.posted_at) return ATOM_ENTRY_TMPL % args
def get(self): logging.info("Saw a GET to /profile handler!") user = users.get_current_user() logging.info("Path = %s" % self.request.path) match = _LOCAL_PROFILE_PATH_RE.match(self.request.path) if not match: self.response.out.write('Badly formed profile URL!') self.response.set_status(400) return # Grab localname; if it's the special @me metavariable, # substitute with the actual users's local profile name # (creating a default on the fly if needed.) localname = match.group(1) if localname == '%40me': profile = ensure_profile(user, self.request.host) else: profile = get_profile_by_uri( make_profile_url(localname, self.request.host)) if not profile: self.response.out.write("Profile not found!") self.response.set_status(404) return # Check to see if currently logged in user is the owner of the profile, and flag if so. is_own_profile = False if user and profile.local_owner: is_own_profile = user.email == profile.local_owner.email #TODO: Fix this up with a GUID # Edit the given profile: m = _PROFILE_RE.match(profile.profile_url) localname = '' if m: assert self.request.host == m.group( 1) # Must match local host for now host_authority = m.group(1) localname = m.group(2) fulluserid = localname + '@' + host_authority template_values = { 'fulluserid': fulluserid, 'is_own_profile': is_own_profile, 'localname': localname, 'nickname': profile.display_name, 'mentions': query_mentions(fulluserid), 'publickey': profile.public_key, 'logout_url': users.create_logout_url(self.request.path), 'login_url': users.create_login_url(self.request.path) } path = os.path.join(os.path.dirname(__file__), 'profile.html') self.response.out.write(template.render(path, template_values))
def get(self): logging.info("Saw a GET to /profile handler!") user = users.get_current_user() logging.info("Path = %s" % self.request.path) match = _LOCAL_PROFILE_PATH_RE.match(self.request.path) if not match: self.response.out.write('Badly formed profile URL!') self.response.set_status(400) return # Grab localname; if it's the special @me metavariable, # substitute with the actual users's local profile name # (creating a default on the fly if needed.) localname = match.group(1) if localname == '%40me': profile = ensure_profile(user, self.request.host) else: profile = get_profile_by_uri(make_profile_url(localname, self.request.host)) if not profile: self.response.out.write("Profile not found!") self.response.set_status(404) return # Check to see if currently logged in user is the owner of the profile, and flag if so. is_own_profile = False if user and profile.local_owner: is_own_profile = user.email == profile.local_owner.email #TODO: Fix this up with a GUID # Edit the given profile: m = _PROFILE_RE.match(profile.profile_url) localname = '' if m: assert self.request.host == m.group(1) # Must match local host for now host_authority = m.group(1) localname = m.group(2) fulluserid = localname + '@' + host_authority template_values = { 'fulluserid': fulluserid, 'is_own_profile': is_own_profile, 'localname': localname, 'nickname': profile.display_name, 'mentions': query_mentions(fulluserid), 'publickey': profile.public_key, 'logout_url': users.create_logout_url(self.request.path), 'login_url' : users.create_login_url(self.request.path) } path = os.path.join(os.path.dirname(__file__), 'profile.html') self.response.out.write(template.render(path, template_values))
def get(self): user_uri = self.request.get('q') host = self.request.headers['Host'] # Is the profile one we know about? logging.info('Getting profile for %s' % user_uri) p = profile_handler.get_profile_by_uri(user_uri) key = p.public_key # The following will recurse if we have no public keys for our # own users, which would be a problem. if not key: key = magicsig.KeyRetriever().LookupPublicKey(user_uri) keyuri = 'data:application/magic-public-key;%s' % key vals = dict(subject=user_uri, keyuri=keyuri, host=host) self.response.out.write(template.render(self.path, vals))
def post(self): # Retrieve putative Salmon from input body. body = self.request.body mime_type = self.request.headers['Content-Type'] protocol = magicsig.MagicEnvelopeProtocol() protocol.key_retriever = RealKeyRetriever() logging.info("Saw body:\n%s\n" % body) envelope = magicsig.Envelope(protocol, document=body, mime_type=mime_type) # If we got here, the Salmon validated. # Grab out the fields of interest: entry = envelope.GetParsedData().getroot() s = et.tostring(entry, encoding='utf-8') logging.info('Saw entry:\n%s\n' % s) ns = '{http://www.w3.org/2005/Atom}' ans = '{http://activitystrea.ms/spec/1.0/}' author = entry.findtext(ns + 'author/' + ns + 'uri') posted_at_str = entry.findtext(ns + 'updated') content = entry.findtext(ns + 'content') if not content: content = entry.findtext(ans + 'object/' + ns + 'content') if not content: content = entry.findtext(ns + 'summary') if not content: content = entry.findtext(ns + 'title') if not content: content = '' content = content.strip() logging.info('Content = %s' % content) # Ensure we have a virtual profile for remote user! p = profile_handler.ensure_virtual_profile( author ) # TODO: WRITE THIS FUNCTION!!! ) mentions = comment_handler.extract_mentions(content) logging.info('About to add: author=%s, content=%s, mentions=%s' % (author, content, mentions)) c = datamodel.Comment( author_profile=p, posted_at=datetime.datetime.now( ), #TODO: should convert posted_at_str, content=content, mentions=mentions) c.put() self.response.set_status(202) self.response.out.write("Salmon accepted!\n")
def post(self): # Retrieve putative Salmon from input body. body = self.request.body mime_type = self.request.headers['Content-Type'] protocol = magicsig.MagicEnvelopeProtocol() protocol.key_retriever = RealKeyRetriever() logging.info("Saw body:\n%s\n" % body) envelope = magicsig.Envelope( protocol, document=body, mime_type=mime_type) # If we got here, the Salmon validated. # Grab out the fields of interest: entry = envelope.GetParsedData().getroot() s = et.tostring(entry,encoding='utf-8') logging.info('Saw entry:\n%s\n' % s) ns = '{http://www.w3.org/2005/Atom}' ans = '{http://activitystrea.ms/spec/1.0/}' author=entry.findtext(ns+'author/'+ns+'uri') posted_at_str=entry.findtext(ns+'updated') content=entry.findtext(ns+'content') if not content: content=entry.findtext(ans+'object/'+ns+'content') if not content: content=entry.findtext(ns+'summary') if not content: content=entry.findtext(ns+'title') if not content: content='' content=content.strip() logging.info('Content = %s' % content) # Ensure we have a virtual profile for remote user! p = profile_handler.ensure_virtual_profile(author) # TODO: WRITE THIS FUNCTION!!! ) mentions = comment_handler.extract_mentions(content) logging.info('About to add: author=%s, content=%s, mentions=%s' % (author, content, mentions)) c = datamodel.Comment( author_profile=p, posted_at=datetime.datetime.now(), #TODO: should convert posted_at_str, content=content, mentions=mentions) c.put() self.response.set_status(202) self.response.out.write("Salmon accepted!\n")
def LookupPublicKey(self, signer_uri): logging.info('Looking up public key for %s' % signer_uri) if not signer_uri: return None xrd_list = self.client.lookup(signer_uri) for item in xrd_list: logging.info("Got webfinger result for %s: %s" % (id, item)) # item is a Xrd proto2, not a string, no need to decode. subject = item.subject key_urls = [link.href for link in item.links if link.rel == 'magic-public-key'] logging.info('Found magic public keys: subject %s, %s' % (subject, key_urls)) # TODO(jpanzer): Yeah, we need key identifiers. KEY_RE=re.compile("data:application/magic-public-key,(RSA.+)") match = KEY_RE.match(key_urls[0]) if match: return match.group(1) else: return None
def LookupPublicKey(self, signer_uri): logging.info('Looking up public key for %s' % signer_uri) if not signer_uri: return None xrd_list = self.client.lookup(signer_uri) for item in xrd_list: logging.info("Got webfinger result for %s: %s" % (id, item)) # item is a Xrd proto2, not a string, no need to decode. subject = item.subject key_urls = [ link.href for link in item.links if link.rel == 'magic-public-key' ] logging.info('Found magic public keys: subject %s, %s' % (subject, key_urls)) # TODO(jpanzer): Yeah, we need key identifiers. KEY_RE = re.compile("data:application/magic-public-key,(RSA.+)") match = KEY_RE.match(key_urls[0]) if match: return match.group(1) else: return None
def do_salmon_slaps(mentions, c): client = webfinger.Client() for id in mentions: try: logging.info('Looking up id %s' % id) xrd_list = client.lookup(id) for item in xrd_list: logging.info("Got webfinger result for %s: %s" % (id, item)) # item is a Xrd proto2, not a string, no need to decode. subject = item.subject slap_urls = key_urls = [ link.href for link in item.links if link.rel == 'http://salmon-protocol.org/ns/salmon-mention' ] logging.info('About to do salmon slaps: subject %s, %s' % (subject, slap_urls)) # Build an envelope: text = to_atom_entry(c) logging.info('signing text: %s' % text) envelope = magicsig.Envelope( raw_data_to_sign=text, data_type='application/atom+xml', signer_uri=c.author_profile.profile_url, signer_key=private_signing_key( c.author_profile.profile_url)) # Now send the envelope: body_to_send = envelope.ToXML() # TODO: Get our own frickin' HTTP client headers = {'Content-Type': 'application/atom+xml'} for url in slap_urls: logging.info('Sending salmon slap to %s' % url) response, content = client._http_client.request( url, 'POST', headers=headers, body=body_to_send) logging.info('Got response %s' % response) except webfinger.FetchError: pass
def do_salmon_slaps(mentions, c): client = webfinger.Client() for id in mentions: try: logging.info('Looking up id %s' % id) xrd_list = client.lookup(id) for item in xrd_list: logging.info("Got webfinger result for %s: %s" % (id, item)) # item is a Xrd proto2, not a string, no need to decode. subject = item.subject slap_urls = key_urls = [link.href for link in item.links if link.rel == 'http://salmon-protocol.org/ns/salmon-mention'] logging.info('About to do salmon slaps: subject %s, %s' % (subject, slap_urls)) # Build an envelope: text = to_atom_entry(c) logging.info('signing text: %s' % text) envelope = magicsig.Envelope( raw_data_to_sign=text, data_type='application/atom+xml', signer_uri=c.author_profile.profile_url, signer_key=private_signing_key(c.author_profile.profile_url)) # Now send the envelope: body_to_send = envelope.ToXML() # TODO: Get our own frickin' HTTP client headers = {'Content-Type' : 'application/atom+xml'} for url in slap_urls: logging.info('Sending salmon slap to %s' % url) response, content = client._http_client.request(url, 'POST', headers=headers, body=body_to_send) logging.info('Got response %s' % response) except webfinger.FetchError: pass