예제 #1
0
    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)
예제 #2
0
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
예제 #3
0
  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)
예제 #4
0
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
예제 #5
0
    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)
예제 #6
0
  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);
예제 #7
0
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
예제 #8
0
    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))
예제 #9
0
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
예제 #10
0
  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))
예제 #11
0
    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))
예제 #12
0
    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")
예제 #13
0
  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))
예제 #14
0
  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")
예제 #15
0
  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
예제 #16
0
    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
예제 #17
0
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
예제 #18
0
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