<reponame>MrTango/python-emails<gh_stars>100-1000
# encoding: utf-8
# This module use pydkim for DKIM signature

# For python2.4:
#  - use dkimpy v0.3 from http://hewgill.com/pydkim/
#  - install hashlib (https://pypi.python.org/pypi/hashlib/20081119) and dnspython

from __future__ import unicode_literals
import logging

from .packages import dkim
from .packages.dkim import DKIMException, UnparsableKeyError
from .packages.dkim.crypto import parse_pem_private_key
from .compat import to_bytes, to_native


class DKIMSigner:

    def __init__(self, selector, domain, key=None, ignore_sign_errors=False, **kwargs):

        self.ignore_sign_errors = ignore_sign_errors
        self._sign_params = kwargs

        privkey = key or kwargs.pop('privkey', None)  # privkey is legacy synonym for `key`

        if not privkey:
            raise TypeError("DKIMSigner.__init__() requires 'key' argument")

        if privkey and hasattr(privkey, 'read'):
            privkey = privkey.read()

        # Compile private key
        try:
            privkey = parse_pem_private_key(to_bytes(privkey))
        except UnparsableKeyError as exc:
            raise DKIMException(exc)

        self._sign_params.update({'privkey': privkey,
                                  'domain': to_bytes(domain),
                                  'selector': to_bytes(selector)})

    def get_sign_string(self, message):
        try:
            # pydkim module parses message and privkey on each signing
            # this is not optimal for mass operations
            # TODO: patch pydkim or use another signing module
            return dkim.sign(message=message, **self._sign_params)
        except DKIMException:
            if self.ignore_sign_errors:
                logging.exception('Error signing message')
            else:
                raise

    def get_sign_bytes(self, message):
        return self.get_sign_string(message)

    def get_sign_header(self, message):
        # pydkim returns string, so we should split
        s = self.get_sign_string(message)
        if s:
            (header, value) = to_native(s).split(': ', 1)
            if value.endswith("\r\n"):
                value = value[:-2]
            return header, value

    def sign_message(self, msg):
        """
        Add DKIM header to email.message
        """

        # py3 pydkim requires bytes to compute dkim header
        # but py3 smtplib requires str to send DATA command (#
        # so we have to convert msg.as_string

        dkim_header = self.get_sign_header(to_bytes(msg.as_string()))
        if dkim_header:
            msg._headers.insert(0, dkim_header)
        return msg

    def sign_message_string(self, message_string):
        """
        Insert DKIM header to message string
        """

        # py3 pydkim requires bytes to compute dkim header
        # but py3 smtplib requires str to send DATA command
        # so we have to convert message_string

        s = self.get_sign_string(to_bytes(message_string))
        return s and to_native(s) + message_string or message_string

    def sign_message_bytes(self, message_bytes):
        """
        Insert DKIM header to message bytes
        """
        s = self.get_sign_bytes(message_bytes)
        return s and to_bytes(s) + message_bytes or message_bytes

# encoding: utf-8
# This module use pydkim for DKIM signature

# For python2.4:
#  - use dkimpy v0.3 from http://hewgill.com/pydkim/
#  - install hashlib (https://pypi.python.org/pypi/hashlib/20081119) and dnspython

from __future__ import unicode_literals
import logging

from .packages import dkim
from .packages.dkim import DKIMException, UnparsableKeyError
from .packages.dkim.crypto import parse_pem_private_key
from .compat import to_bytes, to_native


class DKIMSigner:

    def __init__(self, selector, domain, key=None, ignore_sign_errors=False, **kwargs):

        self.ignore_sign_errors = ignore_sign_errors
        self._sign_params = kwargs

        privkey = key or kwargs.pop('privkey', None)  # privkey is legacy synonym for `key`

        if not privkey:
            raise TypeError("DKIMSigner.__init__() requires 'key' argument")

        if privkey and hasattr(privkey, 'read'):
            privkey = privkey.read()

        # Compile private key
        try:
            privkey = parse_pem_private_key(to_bytes(privkey))
        except UnparsableKeyError as exc:
            raise DKIMException(exc)

        self._sign_params.update({'privkey': privkey,
                                  'domain': to_bytes(domain),
                                  'selector': to_bytes(selector)})

    def get_sign_string(self, message):
        try:
            # pydkim module parses message and privkey on each signing
            # this is not optimal for mass operations
            # TODO: patch pydkim or use another signing module
            return dkim.sign(message=message, **self._sign_params)
        except DKIMException:
            if self.ignore_sign_errors:
                logging.exception('Error signing message')
            else:
                raise

    def get_sign_bytes(self, message):
        return self.get_sign_string(message)

    def get_sign_header(self, message):
        # pydkim returns string, so we should split
        s = self.get_sign_string(message)
        if s:
            (header, value) = to_native(s).split(': ', 1)
            if value.endswith("\r\n"):
                value = value[:-2]
            return header, value

    def sign_message(self, msg):
        """
        Add DKIM header to email.message
        """

        # py3 pydkim requires bytes to compute dkim header
        # but py3 smtplib requires str to send DATA command (#
        # so we have to convert msg.as_string

        dkim_header = self.get_sign_header(to_bytes(msg.as_string()))
        if dkim_header:
            msg._headers.insert(0, dkim_header)
        return msg

    def sign_message_string(self, message_string):
        """
        Insert DKIM header to message string
        """

        # py3 pydkim requires bytes to compute dkim header
        # but py3 smtplib requires str to send DATA command
        # so we have to convert message_string

        s = self.get_sign_string(to_bytes(message_string))
        return s and to_native(s) + message_string or message_string

    def sign_message_bytes(self, message_bytes):
        """
        Insert DKIM header to message bytes
        """
        s = self.get_sign_bytes(message_bytes)
        return s and to_bytes(s) + message_bytes or message_bytes
# encoding: utf-8 # This module use pydkim for DKIM signature # For python2.4: #  - use dkimpy v0.3 from http://hewgill.com/pydkim/ #  - install hashlib (https://pypi.python.org/pypi/hashlib/20081119) and dnspython # privkey is legacy synonym for `key` # Compile private key # pydkim module parses message and privkey on each signing # this is not optimal for mass operations # TODO: patch pydkim or use another signing module # pydkim returns string, so we should split Add DKIM header to email.message # py3 pydkim requires bytes to compute dkim header # but py3 smtplib requires str to send DATA command (# # so we have to convert msg.as_string Insert DKIM header to message string # py3 pydkim requires bytes to compute dkim header # but py3 smtplib requires str to send DATA command # so we have to convert message_string Insert DKIM header to message bytes