def testSigning(self): envelope = magicsig.Envelope(self.protocol, raw_data_to_sign=self.test_atom, signer_uri='acct:[email protected]', signer_key=TEST_PRIVATE_KEY, data_type='application/atom+xml', encoding='base64url', alg='RSA-SHA256') # Turn envelope into text: xml = envelope.ToXML() # Now round-trip it: magicsig.Envelope(self.protocol, mime_type='application/magic-envelope+xml', document=xml)
def testInvalidEnvelopes(self): self.assertRaises(magicsig.EnvelopeError, magicsig.Envelope, 'blah') try: magicsig.Envelope(foo=5, biff=23) # Should never get here self.assertTrue(None) except magicsig.Error: pass
def post(self): """Handles posting back of data and returns a result via XHR. Just for demo purposes. Accepts either data (an XML document) or env (a magic envelope) and returns output of magic-envelope or atom depending on format parameter.""" # TODO: Verify that current user session matches author of content, or throw data = self.request.get('data') envText = self.request.get('env') format = self.request.get('format') or 'magic-envelope' if data: logging.info('posted Atom data = %s\n',data) userid = magicsig.NormalizeUserIdToUri( users.get_current_user().email()) # Do an ACL check to see if current user is the author: if not self.magicenv.IsAllowedSigner(data, userid): logging.info("Authorship check failed for user %s\n",userid) self.response.set_status(400) self.response.out.write("User "+userid+" not first author of entry," " cannot sign.") return # Sign the content on behalf of user: envelope = magicsig.Envelope(raw_data_to_sign=data, data_type='application/atom+xml', signer_uri=userid, signer_key='TEST') #env = self.magicenv.SignMessage(data, 'application/atom+xml', userid) elif envText: logging.info('posted Magic envelope env = %s\n',envText) envelope = magicsig.Envelope(document=envText, mime_type='applicaton/magic-envelope+xml') #env = self.magicenv.Parse(envText) logging.info('Created magic envelope: \n%s\n' % envelope) self.response.set_status(200) # The default if format == 'magic-envelope': self.response.out.write(envelope.ToXML()) elif format == 'atom': self.response.out.write(envelope.ToAtom()) else: self.response.set_status(400) raise "Unsupported format: "+format
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 ParseSalmon(self, text, mimetype): """Parses a salmon from text with given mimetype. Returns: The salmon data as a dict, with fields: """ self.magicenv.key_retriever = self.key_retriever return magicsig.Envelope( self.magicenv, mime_type=mimetype, document=text).ToAtom()
def testToAtom(self): envelope = magicsig.Envelope(self.protocol, raw_data_to_sign=self.test_atom, signer_uri='acct:[email protected]', signer_key=TEST_PRIVATE_KEY, data_type='application/atom+xml', encoding='base64url', alg='RSA-SHA256') text = envelope.ToAtom() assert re.search('atom:entry', text) assert re.search('me:provenance', text) assert re.search('test@example\.com', text)
def testTampering(self): envelope = magicsig.Envelope(self.protocol, raw_data_to_sign=self.test_atom, signer_uri='acct:[email protected]', signer_key=TEST_PRIVATE_KEY, data_type='application/atom+xml', encoding='base64url', alg='RSA-SHA256') xml = envelope.ToXML() self.assertRaises(Exception, magicsig.Envelope, self.protocol, mime_type='application/magic-envelope+xml', document=re.sub('U2FsbW9', 'U2GsbW9', xml))
def post(self): """ Intended to be called via XHR from magicsigdemo.html. """ logging.error('MagicSigDemoVerify post') data = self.request.get('data').strip() logging.info('The data = %s\n',data) env = self.magicenv.Parse(data) try: envelope = magicsig.Envelope(document=data, mime_type='application/magic-envelope+xml') self.response.set_status(200) # The default self.response.out.write("OK") logging.info("SPLASH! Salmon signature verified!") except magicsig.Error: self.response.set_status(400) info = "Details: Exception %s:\n%s\nTraceback:\n%s" % sys.exc_info() logging.info(info) self.response.out.write('Signature does not validate. Details: %s' % info)
def dump(self): envelope = magicsig.Envelope( raw_data_to_sign=self.test_atom, signer_uri='acct:[email protected]', signer_key=TEST_PRIVATE_KEY, data_type='application/atom+xml', encoding='base64url', alg='RSA-SHA256') # Turn envelope into text: xml = envelope.ToXML() # And provenanced Atom: atom = envelope.ToAtom() print "Original data:\n%s\n" % self.test_atom print "Magic Envelope:\n%s\n" % xml print "Atom with provenance:\n%s\n" % atom
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 SignSalmon(self, text, mimetype, requestor_id): """Signs a Salmon on behalfo the the current_user. Input text must be in a recognized format so authorship can be verified. Args: text: Text of message to be signed. mimetype: The MIME type of the message to sign. requestor_id: The id of the requestor (usually current logged in user). Returns: The Magic Envelope parameters from section 3.1 of the Magic Signatures spec, as a dict. """ assert mimetype == 'application/atom+xml' requestor_id = magicsig.NormalizeUserIdToUri(requestor_id) if not self.magicenv.IsAllowedSigner(text, magicsig.NormalizeUserIdToUri(requestor_id)): # TODO: Fix authorship if missing author, raise # exception otherwise. return env = magicsig.Envelope( self.magicenv, raw_data_to_sign=text, signer_uri=requestor_id, signer_key=self._GetKeypair(requestor_id), data_type='application/atom+xml', encoding='base64url', alg='RSA-SHA256') return env.ToXML()