chapps.switchboard module

Communication handlers

This module encapsulates the particular logic of:

  1. receiving data payloads from Postfix, and then

  2. sending back an appropriately-formatted response once the policy manager has had a chance to weigh in on the payload contents

Classes defined here exist mainly to be factories which return the main-loop closure for asyncio.

TODO: RequestHandler should be a subclass of CascadingPolicyHandler which simply only ever has one policy within it. This is to avoid maintaining two nearly-identical code-paths. Running only one policy is obviously a special case of running many.

class chapps.switchboard.CascadingPolicyHandler[source]

Bases: object

Second-generation handler class which cascades multiple yes/no policies

This class started out nearly identical to RequestHandler, but as the software has moved on, so has this handler, which is the main one in general use.

This handler accepts a list of policy manager instances, all of which should produce True/False results. The handler applies each policy to each request, and passes those which pass both, or returns the message from the policy which failed. Once a policy has failed, no further policies are consulted.

Instance attributes:

policies

a list of EmailPolicy objects

pprclass

the class of PostfixPolicyRequest to instantiate from the Postfix request payload

config

a reference to the CHAPPSConfig stored on the first policy in the list

listen_address

the IP address to bind to; see listen_address()

listen_port

the port to listen on; see listen_port()

__init__(policies=[], *, pprclass=<class 'chapps.util.PostfixPolicyRequest'>)[source]
Parameters
property listen_address
property listen_port
async_policy_handler()[source]

Coroutine factory

Returns

a coroutine which handles requests according to the policies, in order

class chapps.switchboard.RequestHandler[source]

Bases: chapps.switchboard.CascadingPolicyHandler

Refactored intermediate base class for wrapping policy managers in an event loop

This class has been reimplemented as a subclass of CascadingPolicyHandler, as a special case which has only one policy to handle.

Instance attributes:

policy

the EmailPolicy manager instance

config

a reference to the CHAPPSConfig stored on the policy instance.

pprclass

a reference to the particular kind of PostfixPolicyRequest to instantiate

__init__(policy, *, pprclass=<class 'chapps.util.PostfixPolicyRequest'>)[source]

Setup a Postfix policy request handler

Parameters

Note

Unlike other class families within CHAPPS, the handlers in this module do not accept config-override arguments. They obtain their references to the config from their attached policy managers.

property listen_address
property listen_port
property policy
class chapps.switchboard.OutboundMultipolicyHandler[source]

Bases: chapps.switchboard.CascadingPolicyHandler

Convenience subclass for combining outbound P/F policies

Could be thought of as a concrete subclass of CascadingPolicyHandler, but meant more as a convenience.

__init__(policies=[], *, pprclass=<class 'chapps.outbound.OutboundPPR'>)[source]

Setup an OutboundMultipolicyHandler

Parameters

If none are provided, default-configured instances of SenderDomainAuthPolicy and OutboundQuotaPolicy are used, in that order.

class chapps.switchboard.OutboundQuotaHandler[source]

Bases: chapps.switchboard.RequestHandler

Convenience class for wrapping OutboundQuotaPolicy

__init__(policy=None)[source]

Setup an OutboundQuotaHandler

Parameters

policy (chapps.policy.OutboundQuotaPolicy) – an instance of OutboundQuotaPolicy

class chapps.switchboard.GreylistingHandler[source]

Bases: chapps.switchboard.RequestHandler

Convenience class for wrapping GreylistingPolicy

__init__(policy=None)[source]

Setup a GreylistingHandler

Parameters

policy (chapps.policy.GreylistingPolicy) – an instance of GreylistingPolicy

class chapps.switchboard.SenderDomainAuthHandler[source]

Bases: chapps.switchboard.RequestHandler

Convenience class for wrapping SenderDomainAuthPolicy

__init__(policy=None)[source]

Setup a SenderDomainAuthHandler

Parameters

policy (chapps.policy.SenderDomainAuthPolicy) – an instance of SenderDomainAuthPolicy

class chapps.switchboard.CascadingMultiresultPolicyHandler[source]

Bases: chapps.switchboard.CascadingPolicyHandler

Cascading handler for policies which produce more than two results

Some policies, such as the SPF enforcement policy, need to be able to generate responses with more nuance than simply pass/fail, and so there is a need for a handler which can deal with policies which return strings (Postfix directives), or possibly a custom class to encapsulate also some idea of pass/fail, in order to know whether to abort the policy-evaluation loop early.

async_policy_handler()[source]

Returns a coroutine which handles results according to the configuration

The policy being enforced is stored in the SPF-related TXT record on the sender’s domain. The local configuration of this policy amounts to instructions about responses to different outcomes of the SPF check, along with what IP address and port to listen on.

This policy handler is different from others in that, because it does not expect a PASS/FAIL response, it simply wraps the return value of approve_policy_request() in a Postfix response packet, and sends it. Rather than refer to pre-configured acceptance and rejection messages, it expects the approval routine to send a string which can be interpreted by Postfix as a command.

TODO: In order to be able to cascade through this kind of policy, it is going to have to return a first-class object which can be annotated as being a pass or a fail, so that a cascading handler can decide whether to continue. That object’s __str__() method will need to return the Postfix command.

class chapps.switchboard.MultiresultPolicyHandler[source]

Bases: chapps.switchboard.CascadingMultiresultPolicyHandler

A subclass for handling just one policy

__init__(policy, *, pprclass=<class 'chapps.util.PostfixPolicyRequest'>)[source]
Parameters
class chapps.switchboard.SPFEnforcementHandler[source]

Bases: chapps.switchboard.MultiresultPolicyHandler

Special handler class for SPFEnforcementPolicy

This one came along last and forced a reconsideration of how all this worked, because it produces more than two possible states as output. The plan is to retrofit all the older policies so that they also can use an action-translation layer, but that will also require some adjustment of the cascading handler.

Note

This class will not be defined if the relevant SPF libraries could not be loaded. They may be installed via pip using the extras mechanism: pip install chapps[SPF]

__init__(policy=None, pprclass=<class 'chapps.inbound.InboundPPR'>)[source]

Set up an SPFEnforcementHandler

Parameters
property policy
class chapps.switchboard.InboundMultipolicyHandler[source]

Bases: chapps.switchboard.CascadingMultiresultPolicyHandler

Implements SPF and Greylisting simultaneously

This is a template for an inbound multipolicy handler, which by default checks SPF and also performs Greylisting, each of which depends upon options which the email account administrator may set about whether either of SPF or Greylisting or both should be applied to inbound mail for the particular domain.

__init__(policies=None, *, pprclass=<class 'chapps.inbound.InboundPPR'>)[source]

Create an inbound policy handler for SPF + Greylisting

Parameters