mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-28 08:03:36 +00:00
Santiago.verify_sender works; commented out old test stubs.
This commit is contained in:
parent
3ffbe02cb6
commit
5cc01cc92d
@ -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.
|
||||
|
||||
@ -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()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user