diff --git a/ugly_hacks/santiago/simplesantiago.py b/ugly_hacks/santiago/simplesantiago.py index 9deae8983..fee9cb190 100644 --- a/ugly_hacks/santiago/simplesantiago.py +++ b/ugly_hacks/santiago/simplesantiago.py @@ -364,16 +364,18 @@ class Santiago(object): allowed to send us messages. """ - if not request.gpg.valid: + gpg_data = request.next() + + if not gpg_data: raise InvalidSignatureError() - if not self.get_host_locations(request.gpg.fingerprint, "santiago"): + if not self.get_host_locations(gpg_data.fingerprint, "santiago"): raise UnwillingHostError( - "{0} is not a Santiago client.".format(request.gpg.fingerprint)) + "{0} is not a Santiago client.".format(gpg_data.fingerprint)) - return request_body + return request - def verify_client(self, request_body, proxied_request): + def verify_client(self, request): """Verify the signature of the message's source. This is part (B) in the message diagram. @@ -387,16 +389,19 @@ class Santiago(object): somebody else. """ - self.verify_client(request_body) + self.verify_sender(request) - if not request_body: + adict = None + try: + adict = dict(request.message) + except: return - if not self.i_am(request_body["to"]): - self.proxy(proxied_request) + if not self.i_am(adict["to"]): + self.proxy(adict["request"]) return - return request_body + return request def decrypt_client(self, request_body): """Decrypt the message and validates the encrypted signature. diff --git a/ugly_hacks/santiago/test_santiago.py b/ugly_hacks/santiago/test_santiago.py index 20ee56cdd..c73022a2c 100644 --- a/ugly_hacks/santiago/test_santiago.py +++ b/ugly_hacks/santiago/test_santiago.py @@ -40,418 +40,512 @@ If I produce a listener that just echoes the parameters, I can validate the resp """ -import unittest +import ConfigParser as configparser import os import sys +import unittest from pprint import pprint import gnupg -import simplesantiago - - -class SantiagoTest(unittest.TestCase): - """The base class for tests.""" - - def setUp(self): - super(TestServing, self).setUp() - - port_a = "localhost:9000" - port_b = "localhost:8000" - - listeners_a = [santiago.SantiagoListener(port_a)] - senders_a = [santiago.SantiagoSender()] - listeners_b = [santiago.SantiagoListener(port_b)] - senders_b = [santiago.SantiagoSender()] - - hosting_a = { "b": { "santiago": [ port_a ]}} - consuming_a = { "santiagao": { "b": [ port_b ]}} - - hosting_b = { "a": { "santiago": [ port_b ], - "wiki": [ "localhost:8001" ]}} - consuming_b = { "santiagao": { "a": [ port_a ]}} - - self.santiago_a = Santiago(listeners_a, senders_a, hosting_a, consuming_a) - self.santiago_b = Santiago(listeners_b, senders_b, hosting_b, consuming_b) - - def serveOnPort(self, port): - """Start listening for connections on a named port. - - Used in testing as a mock listener for responses from a Santiago server. - - """ - class RequestReceiver(object): - """A very basic listener. - - It merely records the calling arguments. - - """ - @cherrypy.expose - def index(self, *args, **kwargs): - self.args = args - self.kwargs = kwargs - - self.socket_port = port - - self.receiver = RequestReceiver() - - cherrypy.quickstart(self.receiver) - - if sys.version_info < (2, 7): - """Add a poor man's forward compatibility.""" - - class ContainsError(AssertionError): - pass - - def assertIn(self, a, b): - if not a in b: - raise self.ContainsError("%s not in %s" % (a, b)) - -class TestClientInitialRequest(SantiagoTest): - """Does the client send a correctly formed request? - - In these tests, we're sending requests to a mock listener which merely - records that the requests were well-formed. - - """ - def setUp(self): - super(SantiagoTest, self).setUp() - - self.serveOnPort(8000) - - def test_request(self): - """Verify that A queues a properly formatted initial request.""" - - self.santiago_a.request(from_="a", to="b", - client="a", host="b", - service="wiki", reply_to="localhost:9001") - - self.assertEqual(self.santiago_a.outgoing_messages, - [{ "from": "a", "to": "b", - "client": "a", "host": "b", - "service": "wiki", "reply-to": "localhost:9001"}]) - - def test_request(self): - """Verify that A sends out a properly formatted initial request.""" - - self.santiago_a.request(from_="a", to="b", - client="a", host="b", - service="wiki", reply_to="localhost:9001") - - self.santiago_a.process() - - self.assertEqual(self.receiver.kwargs, - [{ "from": "a", "to": "b", - "client": "a", "host": "b", - "service": "wiki", "reply-to": "localhost:9001"}]) - -class TestServerInitialRequest(SantiagoTest): - """Test how the Santiago server replies to initial service requests. - - TODO: Add a mock listener to represent A. - TODO: Transform the data structure tests into the mock-response tests. - TODO tests: (normal serving + proxying) * (learning santiagi + not learning) - - Proxying - ~~~~~~~~ - - A host/listener (B) trusts proxied requests according to the minimum trust - in the request. If the request comes from an untrusted proxy or is for an - untrusted client, B ignores it. - - """ - def setUp(self): - super(SantiagoTest, self).setUp() - - self.serveOnPort(9000) - - def test_acknowledgement(self): - """If B receives an authorized request, then it replies with a location. - - An "authorized request" in this case is for a service from a client that - B is willing to host that service for. - - In this case, B will answer with the wiki's location. - - """ - self.santiago_b.receive(from_="a", to="b", - client="a", host="b", - service="wiki", reply_to=None) - - self.assertEqual(self.santiago_b.outgoing_messages, - [{"from": "b", - "to": "a", - "client": "a", - "host": "b", - "service": "wiki", - "locations": ["192.168.0.13"], - "reply-to": "localhost:8000"}]) - - def test_reject_bad_service(self): - """Does B reject requests for unsupported services? - - In this case, B should reply with an empty list of locations. - - """ - self.santiago_b.receive(from_="a", to="b", - client="a", host="b", - service="wiki", reply_to=None) - - self.assertEqual(self.santiago_b.outgoing_messages, - [{"from": "b", - "to": "a", - "client": "a", - "host": "b", - "service": "wiki", - "locations": [], - "reply-to": "localhost:8000"}]) - - def test_reject_bad_key(self): - """If B receives a request from an unauthorized key, it does not reply. - - An "unauthorized request" in this case is for a service from a client - that B does not trust. This is different than clients B hosts no - services for. - - In this case, B will never answer the request. - - """ - self.santiago_b.receive(from_="a", to="b", - client="z", host="b", - service="wiki", reply_to=None) - - self.assertEqual(self.santiago_b.outgoing_messages, []) - - def test_reject_good_source_bad_client(self): - """B is silent when a trusted key proxies anything for an untrusted key. - - B doesn't know who the client is and should consider it an - untrusted key connection attempt. - - """ - self.santiago_b.receive(from_="a", to="b", - client="z", host="b", - service="wiki", reply_to=None) - - self.assertEqual(self.santiago_b.outgoing_messages, []) - - def test_reject_bad_source_good_client(self): - """B is silent when an untrusted key proxies anything for a trusted key. - - B doesn't know who the proxy is and should consider it an - untrusted key connection attempt. - - """ - self.santiago_b.receive(from_="z", to="b", - client="a", host="b", - service="wiki", reply_to=None) - - self.assertEqual(self.santiago_b.outgoing_messages, []) - - def test_reject_bad_source_bad_client(self): - """B is silent when untrusted keys proxy anything for untrusted keys. - - B doesn't know who anybody is and considers this an untrusted - connection attempt. - - """ - self.santiago_b.receive(from_="y", to="b", - client="z", host="b", - service="wiki", reply_to=None) - - self.assertEqual(self.santiago_b.outgoing_messages, []) - - def test_learn_santaigo(self): - """Does B learn new Santiago locations from trusted requests? - - If A sends B a request with a new Santiago location, B should learn it. - - """ - self.santiago_b.receive(from_="a", to="b", - client="a", host="b", - service="wiki", reply_to="localhost:9001") - - self.assertEqual(self.santiago_b.consuming["santiago"]["a"], - ["localhost:9000", "localhost:9001"]) - - def test_handle_requests_once(self): - """Verify that we reply to each request only once.""" - - self.santiago_b.receive(from_="a", to="b", - client="a", host="b", - service="wiki", reply_to=None) - self.santiago_b.process() - - self.assertEqual(self.santiago_b.outgoing_messages, []) - -class TestServerInitialResponse(SantiagoTest): - pass - -class TestClientInitialResponse(SantiagoTest): - pass - -class TestForwardedRequest(SantiagoTest): - pass - -class TestForwardedResponse(SantiagoTest): - pass - -class TestSimpleSantiago(unittest.TestCase): - def setUp(self): - - port_a = "localhost:9000" - port_b = "localhost:8000" - - listeners_a = {"http": {"port": port_a}} - senders_a = ({ "protocol": "http", "proxy": tor_proxy_port },) - - listeners_b = {"http": {"port": port_b}} - senders_b = ({ "protocol": "http", "proxy": tor_proxy_port },) - - hosting_a = { "b": { "santiago": set( ["aDifferentHexNumber.onion"])}} - consuming_a = { "santiagao": {"b": set(["iAmAHexadecimalNumber.onion"])}} - - hosting_b = { "a": { "santiago": set( ["iAmAHexadecimalNumber.onion"])}} - consuming_b = { "santiagao": { "a": set( ["aDifferentHexNumber.onion"])}} - - self.santiago_a = SimpleSantiago(listeners_a, senders_a, - hosting_a, consuming_a, "a") - self.santiago_b = SimpleSantiago(listeners_b, senders_b, - hosting_b, consuming_b, "b") - - cherrypy.Application(self.santiago_a, "/") - cherrypy.Application(self.santiago_b, "/") - - cherrypy.engine.start() - - def testRequest(self): - self.santiago_a.request(from_="a", to="b", - client="a", host="b", - service="wiki", reply_to="localhost:9000") - - -class Unwrapping(unittest.TestCase): - - def testVerifySigner(self): - pass - - def testVerifyClient(self): - pass - - def testDecryptClient(self): - pass - -class IncomingProxyRequest(unittest.TestCase): - - """Do we correctly handle valid, incoming, proxied messages? - - These tests are for the first wrapped layer of the message, that which is - signed by the sender. The sender is not necessarily the original requester - who's asking us to do something with the message. +import logging +from errors import InvalidSignatureError, UnwillingHostError +import simplesantiago as santiago +import test_pgpprocessor +import pgpprocessor + + +# class SantiagoTest(unittest.TestCase): +# """The base class for tests.""" +# +# def setUp(self): +# super(TestServing, self).setUp() +# +# port_a = "localhost:9000" +# port_b = "localhost:8000" +# +# listeners_a = [santiago.SantiagoListener(port_a)] +# senders_a = [santiago.SantiagoSender()] +# listeners_b = [santiago.SantiagoListener(port_b)] +# senders_b = [santiago.SantiagoSender()] +# +# hosting_a = { "b": { "santiago": [ port_a ]}} +# consuming_a = { "santiagao": { "b": [ port_b ]}} +# +# hosting_b = { "a": { "santiago": [ port_b ], +# "wiki": [ "localhost:8001" ]}} +# consuming_b = { "santiagao": { "a": [ port_a ]}} +# +# self.santiago_a = Santiago(listeners_a, senders_a, hosting_a, consuming_a) +# self.santiago_b = Santiago(listeners_b, senders_b, hosting_b, consuming_b) +# +# def serveOnPort(self, port): +# """Start listening for connections on a named port. +# +# Used in testing as a mock listener for responses from a Santiago server. +# +# """ +# class RequestReceiver(object): +# """A very basic listener. +# +# It merely records the calling arguments. +# +# """ +# @cherrypy.expose +# def index(self, *args, **kwargs): +# self.args = args +# self.kwargs = kwargs +# +# self.socket_port = port +# +# self.receiver = RequestReceiver() +# +# cherrypy.quickstart(self.receiver) +# +# if sys.version_info < (2, 7): +# """Add a poor man's forward compatibility.""" +# +# class ContainsError(AssertionError): +# pass +# +# def assertIn(self, a, b): +# if not a in b: +# raise self.ContainsError("%s not in %s" % (a, b)) +# +# class TestClientInitialRequest(SantiagoTest): +# """Does the client send a correctly formed request? +# +# In these tests, we're sending requests to a mock listener which merely +# records that the requests were well-formed. +# +# """ +# def setUp(self): +# super(SantiagoTest, self).setUp() +# +# self.serveOnPort(8000) +# +# def test_request(self): +# """Verify that A queues a properly formatted initial request.""" +# +# self.santiago_a.request(from_="a", to="b", +# client="a", host="b", +# service="wiki", reply_to="localhost:9001") +# +# self.assertEqual(self.santiago_a.outgoing_messages, +# [{ "from": "a", "to": "b", +# "client": "a", "host": "b", +# "service": "wiki", "reply-to": "localhost:9001"}]) +# +# def test_request(self): +# """Verify that A sends out a properly formatted initial request.""" +# +# self.santiago_a.request(from_="a", to="b", +# client="a", host="b", +# service="wiki", reply_to="localhost:9001") +# +# self.santiago_a.process() +# +# self.assertEqual(self.receiver.kwargs, +# [{ "from": "a", "to": "b", +# "client": "a", "host": "b", +# "service": "wiki", "reply-to": "localhost:9001"}]) +# +# class TestServerInitialRequest(SantiagoTest): +# """Test how the Santiago server replies to initial service requests. +# +# TODO: Add a mock listener to represent A. +# TODO: Transform the data structure tests into the mock-response tests. +# TODO tests: (normal serving + proxying) * (learning santiagi + not learning) +# +# Proxying +# ~~~~~~~~ +# +# A host/listener (B) trusts proxied requests according to the minimum trust +# in the request. If the request comes from an untrusted proxy or is for an +# untrusted client, B ignores it. +# +# """ +# def setUp(self): +# super(SantiagoTest, self).setUp() +# +# self.serveOnPort(9000) +# +# def test_acknowledgement(self): +# """If B receives an authorized request, then it replies with a location. +# +# An "authorized request" in this case is for a service from a client that +# B is willing to host that service for. +# +# In this case, B will answer with the wiki's location. +# +# """ +# self.santiago_b.receive(from_="a", to="b", +# client="a", host="b", +# service="wiki", reply_to=None) +# +# self.assertEqual(self.santiago_b.outgoing_messages, +# [{"from": "b", +# "to": "a", +# "client": "a", +# "host": "b", +# "service": "wiki", +# "locations": ["192.168.0.13"], +# "reply-to": "localhost:8000"}]) +# +# def test_reject_bad_service(self): +# """Does B reject requests for unsupported services? +# +# In this case, B should reply with an empty list of locations. +# +# """ +# self.santiago_b.receive(from_="a", to="b", +# client="a", host="b", +# service="wiki", reply_to=None) +# +# self.assertEqual(self.santiago_b.outgoing_messages, +# [{"from": "b", +# "to": "a", +# "client": "a", +# "host": "b", +# "service": "wiki", +# "locations": [], +# "reply-to": "localhost:8000"}]) +# +# def test_reject_bad_key(self): +# """If B receives a request from an unauthorized key, it does not reply. +# +# An "unauthorized request" in this case is for a service from a client +# that B does not trust. This is different than clients B hosts no +# services for. +# +# In this case, B will never answer the request. +# +# """ +# self.santiago_b.receive(from_="a", to="b", +# client="z", host="b", +# service="wiki", reply_to=None) +# +# self.assertEqual(self.santiago_b.outgoing_messages, []) +# +# def test_reject_good_source_bad_client(self): +# """B is silent when a trusted key proxies anything for an untrusted key. +# +# B doesn't know who the client is and should consider it an +# untrusted key connection attempt. +# +# """ +# self.santiago_b.receive(from_="a", to="b", +# client="z", host="b", +# service="wiki", reply_to=None) +# +# self.assertEqual(self.santiago_b.outgoing_messages, []) +# +# def test_reject_bad_source_good_client(self): +# """B is silent when an untrusted key proxies anything for a trusted key. +# +# B doesn't know who the proxy is and should consider it an +# untrusted key connection attempt. +# +# """ +# self.santiago_b.receive(from_="z", to="b", +# client="a", host="b", +# service="wiki", reply_to=None) +# +# self.assertEqual(self.santiago_b.outgoing_messages, []) +# +# def test_reject_bad_source_bad_client(self): +# """B is silent when untrusted keys proxy anything for untrusted keys. +# +# B doesn't know who anybody is and considers this an untrusted +# connection attempt. +# +# """ +# self.santiago_b.receive(from_="y", to="b", +# client="z", host="b", +# service="wiki", reply_to=None) +# +# self.assertEqual(self.santiago_b.outgoing_messages, []) +# +# def test_learn_santaigo(self): +# """Does B learn new Santiago locations from trusted requests? +# +# If A sends B a request with a new Santiago location, B should learn it. +# +# """ +# self.santiago_b.receive(from_="a", to="b", +# client="a", host="b", +# service="wiki", reply_to="localhost:9001") +# +# self.assertEqual(self.santiago_b.consuming["santiago"]["a"], +# ["localhost:9000", "localhost:9001"]) +# +# def test_handle_requests_once(self): +# """Verify that we reply to each request only once.""" +# +# self.santiago_b.receive(from_="a", to="b", +# client="a", host="b", +# service="wiki", reply_to=None) +# self.santiago_b.process() +# +# self.assertEqual(self.santiago_b.outgoing_messages, []) +# +# class TestServerInitialResponse(SantiagoTest): +# pass +# +# class TestClientInitialResponse(SantiagoTest): +# pass +# +# class TestForwardedRequest(SantiagoTest): +# pass +# +# class TestForwardedResponse(SantiagoTest): +# pass +# +# class TestSimpleSantiago(unittest.TestCase): +# def setUp(self): +# +# port_a = "localhost:9000" +# port_b = "localhost:8000" +# +# listeners_a = {"http": {"port": port_a}} +# senders_a = ({ "protocol": "http", "proxy": tor_proxy_port },) +# +# listeners_b = {"http": {"port": port_b}} +# senders_b = ({ "protocol": "http", "proxy": tor_proxy_port },) +# +# hosting_a = { "b": { "santiago": set( ["aDifferentHexNumber.onion"])}} +# consuming_a = { "santiagao": {"b": set(["iAmAHexadecimalNumber.onion"])}} +# +# hosting_b = { "a": { "santiago": set( ["iAmAHexadecimalNumber.onion"])}} +# consuming_b = { "santiagao": { "a": set( ["aDifferentHexNumber.onion"])}} +# +# self.santiago_a = santiago.Santiago(listeners_a, senders_a, +# hosting_a, consuming_a, "a") +# self.santiago_b = santiago.Santiago(listeners_b, senders_b, +# hosting_b, consuming_b, "b") +# +# cherrypy.Application(self.santiago_a, "/") +# cherrypy.Application(self.santiago_b, "/") +# +# cherrypy.engine.start() +# +# def testRequest(self): +# self.santiago_a.request(from_="a", to="b", +# client="a", host="b", +# service="wiki", reply_to="localhost:9000") +# +# +# class Unwrapping(unittest.TestCase): +# +# def testVerifySigner(self): +# pass +# +# def testVerifyClient(self): +# pass +# +# def testDecryptClient(self): +# pass +# +# class IncomingProxyRequest(unittest.TestCase): +# +# """Do we correctly handle valid, incoming, proxied messages? +# +# These tests are for the first wrapped layer of the message, that which is +# signed by the sender. The sender is not necessarily the original requester +# who's asking us to do something with the message. +# +# """ +# +# def setUp(self): +# pass +# +# def testPassingMessage(self): +# """Does a valid proxied message pass?""" +# +# pass +# +# def testInvalidSig(self): +# """Does an invalid signature raise an error?""" +# +# pass +# +# def testUnknownClient(self): +# """Does an unknown client raise an error?""" +# +# pass +# +# class IncomingSignedRequest(IncomingProxyRequest): +# +# """Do we correctly handle valid, incoming, messages? +# +# These tests focus on the second layer of the message which is signed by the +# host/client and lists a destination. +# +# """ +# def testProxyOtherHosts(self): +# """Messages to others are sent to them directly or proxied.""" +# +# pass +# +# def testHandleMyHosting(self): +# """Messages to me are not proxied and handled normally.""" +# +# pass +# +# def testNoDestination(self): +# """Messages without destinations are ignored.""" +# +# pass +# +# class IncomingRequestBody(IncomingSignedRequest): +# +# """Do we correctly handle the body of a request? +# +# This is the last layer of the message which is encrypted by the original +# sender. This validation also depends on the previous layer's data, making +# it a bit more complicated. +# +# """ +# def testHandleGoodMessage(self): +# """Sanity check: no errors are thrown for a valid message.""" +# +# pass +# +# def testCantDecryptMessage(self): +# """This message isn't for me. I can't decrypt it.""" +# +# pass +# +# def testImNotHost(self): +# """Bail out if someone else is the host, yet I am the "to".""" +# +# pass +# +# def testImNotClient(self): +# """Bail out if someone else is the client, yet I am the "to".""" +# +# pass +# +# def testHostAndClient(self): +# """Bail out if the message includes a host and a client. +# +# A circular response? +# +# """ +# pass +# +# def testImNotTo(self): +# """This message isn't for me. +# +# The "To" has been repeated from the signed message, but I'm not the +# recipient in the encrypted message. +# +# """ +# pass +# +# def testNoDestinations(self): +# """No host, client, or to.""" +# +# pass +# +# def testSignersDiffer(self): +# """The signed message and encrypted message have different signers.""" +# +# pass +# +# def testSignerAndClientDiffer(self): +# """The encrypted message is signed by someone other than the cilent.""" +# +# pass + +class VerifySender(test_pgpprocessor.MessageWrapper): + """Santiago.verify_sender performs as expected. + + It must unwrap the message and return the message's (decrypted) body. If + stuff is weird about the message, raise errors: + + - Raise an InvalidSignature error when the signature is incorrect. + + - Raise an UnwillingHost error when the signer is not a client authorized to + send us Santiago messages. """ def setUp(self): - pass + super(VerifySender, self).setUp() - def testPassingMessage(self): - """Does a valid proxied message pass?""" + self.santiago = santiago.Santiago( + hosting = { self.keyid: {"santiago": ["1"] }}, + me = self.keyid) - + self.method = "verify_sender" - pass + self.unwrapper = pgpprocessor.Unwrapper(str(self.messages[2])) - def testInvalidSig(self): - """Does an invalid signature raise an error?""" + def test_valid_message(self): + """A valid message (correctly signed and from a trusted host) passes.""" - pass + gpg_data = getattr(self.santiago, self.method)(self.unwrapper) - def testUnknownClient(self): - """Does an unknown client raise an error?""" + self.assertEqual(self.messages[1], gpg_data.message) - pass + def test_fail_invalid_signature(self): + """A message with an invalid signature fails -class IncomingSignedRequest(IncomingProxyRequest): - - """Do we correctly handle valid, incoming, messages? - - These tests focus on the second layer of the message which is signed by the - host/client and lists a destination. - - """ - def testProxyOtherHosts(self): - """Messages to others are sent to them directly or proxied.""" - - pass - - def testHandleMyHosting(self): - """Messages to me are not proxied and handled normally.""" - - pass - - def testNoDestination(self): - """Messages without destinations are ignored.""" - - pass - -class IncomingRequestBody(IncomingSignedRequest): - - """Do we correctly handle the body of a request? - - This is the last layer of the message which is encrypted by the original - sender. This validation also depends on the previous layer's data, making - it a bit more complicated. - - """ - def testHandleGoodMessage(self): - """Sanity check: no errors are thrown for a valid message.""" - - pass - - def testCantDecryptMessage(self): - """This message isn't for me. I can't decrypt it.""" - - pass - - def testImNotHost(self): - """Bail out if someone else is the host, yet I am the "to".""" - - pass - - def testImNotClient(self): - """Bail out if someone else is the client, yet I am the "to".""" - - pass - - def testHostAndClient(self): - """Bail out if the message includes a host and a client. - - A circular response? + It raises an InvalidSignature error. """ - pass + message = self.unwrapper.message.splitlines(True) + message[7] += "q" + self.unwrapper.message = "".join(message) - def testImNotTo(self): - """This message isn't for me. + self.assertRaises(InvalidSignatureError, + getattr(self.santiago, self.method), self.unwrapper) - The "To" has been repeated from the signed message, but I'm not the - recipient in the encrypted message. + def test_fail_invalid_signer(self): + """A message with a valid signature from an untrusted signer fails. + + It raises an UntrustedClient error. """ - pass + self.santiago.hosting = { 1: { "santiago": ["1"] }} - def testNoDestinations(self): - """No host, client, or to.""" + self.assertRaises(UnwillingHostError, + getattr(self.santiago, self.method), self.unwrapper) + +class VerifyClient(VerifySender): + """Santiago.verify_client performs as expected. + + It must unwrap the message and return the message's (decrypted) body. If + stuff is weird about the message, raise errors: + + - Raise an InvalidSignature error when the signature is incorrect. + + - Raise an UnwillingHost error when the signer is not a client authorized to + send us Santiago messages. + + Is this just unnecessarily fucking complicating all of this? Yes. Screw + proxying, just get it out the door by sending the encrypted bits directly. + + """ + def setUp(self): + super(VerifyClient, self).__init__() + + self.method = "verify_client" + + def test_proxy_request(self): + """When the message is for somebody else, it gets proxied.""" pass - def testSignersDiffer(self): - """The signed message and encrypted message have different signers.""" + def test_return_only_valid_message(self): + """Invalid messages (without "to" and "request" keys) return nothing.""" pass - def testSignerAndClientDiffer(self): - """The encrypted message is signed by someone other than the cilent.""" + def test_dont_verify_source(self): + """If the message is being proxied, we don't care who sent the message. + """ pass def show(name, item, iterations=1): @@ -465,4 +559,5 @@ def show(name, item, iterations=1): pprint(item) if __name__ == "__main__": + logging.disable(logging.CRITICAL) unittest.main()