rpms/python-twisted-core/F-13 changeset_r25457.patch, 1.2, 1.3 python-twisted-core.spec, 1.16, 1.17

Thomas Vander Stichele thomasvs at fedoraproject.org
Tue Apr 20 07:53:01 UTC 2010


Author: thomasvs

Update of /cvs/pkgs/rpms/python-twisted-core/F-13
In directory cvs01.phx2.fedoraproject.org:/tmp/cvs-serv11272

Modified Files:
	changeset_r25457.patch python-twisted-core.spec 
Log Message:
update for further deprecation warnings

changeset_r25457.patch:
 conch/test/test_ckeygen.py    |   73 ++++
 cred/util.py                  |   30 +
 internet/_sslverify.py        |    4 
 internet/_sslverify.py.orig   |  745 ++++++++++++++++++++++++++++++++++++++++++
 internet/_sslverify.py.rej    |   18 +
 persisted/sob.py              |    9 
 protocols/sip.py              |   12 
 python/filepath.py            |    4 
 python/hashlib.py             |   24 +
 python/otp.py                 |   57 ++-
 python/test/test_hashlib.py   |   90 +++++
 python/test/test_zipstream.py |    6 
 spread/pb.py                  |   12 
 test/test_newcred.py          |   49 ++
 trial/test/test_loader.py     |    4 
 words/test/test_oscar.py      |   24 +
 16 files changed, 1100 insertions(+), 61 deletions(-)

Index: changeset_r25457.patch
===================================================================
RCS file: /cvs/pkgs/rpms/python-twisted-core/F-13/changeset_r25457.patch,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -p -r1.2 -r1.3
--- changeset_r25457.patch	18 Apr 2010 10:42:37 -0000	1.2
+++ changeset_r25457.patch	20 Apr 2010 07:53:01 -0000	1.3
@@ -1,20 +1,145 @@
-diff -aur TwistedCore-8.2.0/twisted/internet/_sslverify.py TwistedCore-8.2.0.patched/twisted/internet/_sslverify.py
---- TwistedCore-8.2.0/twisted/internet/_sslverify.py	2008-11-20 19:36:39.000000000 +0100
-+++ TwistedCore-8.2.0.patched/twisted/internet/_sslverify.py	2010-04-15 13:03:35.000000000 +0200
-@@ -2,10 +2,11 @@
- # Copyright 2005 Divmod, Inc.  See LICENSE file for details
- # Copyright (c) 2005-2008 Twisted Matrix Laboratories.
- 
--import itertools, md5
-+import itertools
- from OpenSSL import SSL, crypto
+diff -Naur TwistedCore-8.2.0/twisted/conch/test/test_ckeygen.py TwistedCore-8.2.0.patched/twisted/conch/test/test_ckeygen.py
+--- TwistedCore-8.2.0/twisted/conch/test/test_ckeygen.py	1970-01-01 01:00:00.000000000 +0100
++++ TwistedCore-8.2.0.patched/twisted/conch/test/test_ckeygen.py	2010-04-20 09:43:12.000000000 +0200
+@@ -0,0 +1,73 @@
++# Copyright (c) 2008 Twisted Matrix Laboratories.
++# See LICENSE for details.
++
++"""
++Tests for L{twisted.conch.scripts.ckeygen}.
++"""
++
++import sys
++from StringIO import StringIO
++
++from twisted.python.filepath import FilePath
++from twisted.trial.unittest import TestCase
++from twisted.conch.ssh.keys import Key
++from twisted.conch.scripts.ckeygen import printFingerprint, _saveKey
++from twisted.conch.test.keydata import publicRSA_openssh, privateRSA_openssh
++
++
++
++class KeyGenTests(TestCase):
++    """
++    Tests for various functions used to implement the I{ckeygen} script.
++    """
++    def setUp(self):
++        """
++        Patch C{sys.stdout} with a L{StringIO} instance to tests can make
++        assertions about what's printed.
++        """
++        self.stdout = StringIO()
++        self.patch(sys, 'stdout', self.stdout)
++
++
++    def test_printFingerprint(self):
++        """
++        L{printFingerprint} writes a line to standard out giving the number of
++        bits of the key, its fingerprint, and the basename of the file from it
++        was read.
++        """
++        filename = self.mktemp()
++        FilePath(filename).setContent(publicRSA_openssh)
++        printFingerprint({'filename': filename})
++        self.assertEqual(
++            self.stdout.getvalue(),
++            '768 3d:13:5f:cb:c9:79:8a:93:06:27:65:bc:3d:0b:8f:af temp\n')
++
++
++    def test_saveKey(self):
++        """
++        L{_saveKey} writes the private and public parts of a key to two
++        different files and writes a report of this to standard out.
++        """
++        base = FilePath(self.mktemp())
++        base.makedirs()
++        filename = base.child('id_rsa').path
++        key = Key.fromString(privateRSA_openssh)
++        _saveKey(
++            key.keyObject,
++            {'filename': filename, 'pass': 'passphrase'})
++        self.assertEqual(
++            self.stdout.getvalue(),
++            "Your identification has been saved in %s\n"
++            "Your public key has been saved in %s.pub\n"
++            "The key fingerprint is:\n"
++            "3d:13:5f:cb:c9:79:8a:93:06:27:65:bc:3d:0b:8f:af\n" % (
++                filename,
++                filename))
++        self.assertEqual(
++            key.fromString(
++                base.child('id_rsa').getContent(), None, 'passphrase'),
++            key)
++        self.assertEqual(
++            Key.fromString(base.child('id_rsa.pub').getContent()),
++            key.public())
++
+diff -Naur TwistedCore-8.2.0/twisted/cred/util.py TwistedCore-8.2.0.patched/twisted/cred/util.py
+--- TwistedCore-8.2.0/twisted/cred/util.py	2008-07-29 22:13:54.000000000 +0200
++++ TwistedCore-8.2.0.patched/twisted/cred/util.py	2010-04-20 09:43:18.000000000 +0200
+@@ -1,30 +1,32 @@
+-
+-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
++# -*- test-case-name: twisted.test.test_newcred -*-
++# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
+ # See LICENSE for details.
+ 
+-
+ """
+-Utility functions for authorization.
++Outdated, deprecated functionality related to challenge-based authentication.
+ 
+-These are currently for challenge-response shared secret authentication.
+-
+-Maintainer: Glyph Lefkowitz
++Seek a solution to your problem elsewhere.  This module is deprecated.
+ """
+ 
+ # System Imports
+-import md5
+-import random
++import random, warnings
  
- from twisted.python import reflect, util
 +from twisted.python.hashlib import md5
- from twisted.internet.defer import Deferred
- from twisted.internet.error import VerifyError, CertificateError
+ from twisted.cred.error import Unauthorized
  
-@@ -452,7 +453,7 @@
++
+ def respond(challenge, password):
+     """Respond to a challenge.
+     This is useful for challenge/response authentication.
+     """
+-    m = md5.new()
++    warnings.warn(
++        "twisted.cred.util.respond is deprecated since Twisted 8.3.",
++        category=PendingDeprecationWarning,
++        stacklevel=2)
++    m = md5()
+     m.update(password)
+     hashedPassword = m.digest()
+-    m = md5.new()
++    m = md5()
+     m.update(hashedPassword)
+     m.update(challenge)
+     doubleHashedPassword = m.digest()
+@@ -33,8 +35,12 @@
+ def challenge():
+     """I return some random data.
+     """
++    warnings.warn(
++        "twisted.cred.util.challenge is deprecated since Twisted 8.3.",
++        category=PendingDeprecationWarning,
++        stacklevel=2)
+     crap = ''
+     for x in range(random.randrange(15,25)):
+         crap = crap + chr(random.randint(65,90))
+-    crap = md5.new(crap).digest()
++    crap = md5(crap).digest()
+     return crap
+diff -Naur TwistedCore-8.2.0/twisted/internet/_sslverify.py TwistedCore-8.2.0.patched/twisted/internet/_sslverify.py
+--- TwistedCore-8.2.0/twisted/internet/_sslverify.py	2008-11-20 19:36:39.000000000 +0100
++++ TwistedCore-8.2.0.patched/twisted/internet/_sslverify.py	2010-04-20 09:43:18.000000000 +0200
+@@ -452,7 +452,7 @@
          MD5 hex digest of signature on an empty certificate request with this
          key.
          """
@@ -23,7 +148,7 @@ diff -aur TwistedCore-8.2.0/twisted/inte
  
  
      def inspect(self):
-@@ -736,7 +737,7 @@
+@@ -736,7 +736,7 @@
              ctx.set_options(self._OP_ALL)
  
          if self.enableSessions:
@@ -32,11 +157,821 @@ diff -aur TwistedCore-8.2.0/twisted/inte
              ctx.set_session_id(sessionName)
  
          if not self.enableSessionTickets:
-Only in TwistedCore-8.2.0.patched/twisted/internet: _sslverify.py.orig
-Only in TwistedCore-8.2.0.patched/twisted/internet: _sslverify.py.rej
-diff -aur TwistedCore-8.2.0/twisted/protocols/sip.py TwistedCore-8.2.0.patched/twisted/protocols/sip.py
+diff -Naur TwistedCore-8.2.0/twisted/internet/_sslverify.py.orig TwistedCore-8.2.0.patched/twisted/internet/_sslverify.py.orig
+--- TwistedCore-8.2.0/twisted/internet/_sslverify.py.orig	1970-01-01 01:00:00.000000000 +0100
++++ TwistedCore-8.2.0.patched/twisted/internet/_sslverify.py.orig	2008-11-20 19:36:39.000000000 +0100
+@@ -0,0 +1,745 @@
++# -*- test-case-name: twisted.test.test_sslverify -*-
++# Copyright 2005 Divmod, Inc.  See LICENSE file for details
++# Copyright (c) 2005-2008 Twisted Matrix Laboratories.
++
++import itertools, md5
++from OpenSSL import SSL, crypto
++
++from twisted.python import reflect, util
++from twisted.internet.defer import Deferred
++from twisted.internet.error import VerifyError, CertificateError
++
++# Private - shared between all OpenSSLCertificateOptions, counts up to provide
++# a unique session id for each context
++_sessionCounter = itertools.count().next
++
++_x509names = {
++    'CN': 'commonName',
++    'commonName': 'commonName',
++
++    'O': 'organizationName',
++    'organizationName': 'organizationName',
++
++    'OU': 'organizationalUnitName',
++    'organizationalUnitName': 'organizationalUnitName',
++
++    'L': 'localityName',
++    'localityName': 'localityName',
++
++    'ST': 'stateOrProvinceName',
++    'stateOrProvinceName': 'stateOrProvinceName',
++
++    'C': 'countryName',
++    'countryName': 'countryName',
++
++    'emailAddress': 'emailAddress'}
++
++
++class DistinguishedName(dict):
++    """
++    Identify and describe an entity.
++
++    Distinguished names are used to provide a minimal amount of identifying
++    information about a certificate issuer or subject.  They are commonly
++    created with one or more of the following fields::
++
++        commonName (CN)
++        organizationName (O)
++        organizationalUnitName (OU)
++        localityName (L)
++        stateOrProvinceName (ST)
++        countryName (C)
++        emailAddress
++    """
++    __slots__ = ()
++
++    def __init__(self, **kw):
++        for k, v in kw.iteritems():
++            setattr(self, k, v)
++
++
++    def _copyFrom(self, x509name):
++        d = {}
++        for name in _x509names:
++            value = getattr(x509name, name, None)
++            if value is not None:
++                setattr(self, name, value)
++
++
++    def _copyInto(self, x509name):
++        for k, v in self.iteritems():
++            setattr(x509name, k, v)
++
++
++    def __repr__(self):
++        return '<DN %s>' % (dict.__repr__(self)[1:-1])
++
++
++    def __getattr__(self, attr):
++        try:
++            return self[_x509names[attr]]
++        except KeyError:
++            raise AttributeError(attr)
++
++
++    def __setattr__(self, attr, value):
++        assert type(attr) is str
++        if not attr in _x509names:
++            raise AttributeError("%s is not a valid OpenSSL X509 name field" % (attr,))
++        realAttr = _x509names[attr]
++        value = value.encode('ascii')
++        assert type(value) is str
++        self[realAttr] = value
++
++
++    def inspect(self):
++        """
++        Return a multi-line, human-readable representation of this DN.
++        """
++        l = []
++        lablen = 0
++        def uniqueValues(mapping):
++            return dict.fromkeys(mapping.itervalues()).keys()
++        for k in uniqueValues(_x509names):
++            label = util.nameToLabel(k)
++            lablen = max(len(label), lablen)
++            v = getattr(self, k, None)
++            if v is not None:
++                l.append((label, v))
++        lablen += 2
++        for n, (label, attr) in enumerate(l):
++            l[n] = (label.rjust(lablen)+': '+ attr)
++        return '\n'.join(l)
++
++DN = DistinguishedName
++
++
++class CertBase:
++    def __init__(self, original):
++        self.original = original
++
++    def _copyName(self, suffix):
++        dn = DistinguishedName()
++        dn._copyFrom(getattr(self.original, 'get_'+suffix)())
++        return dn
++
++    def getSubject(self):
++        """
++        Retrieve the subject of this certificate.
++
++        @rtype: L{DistinguishedName}
++        @return: A copy of the subject of this certificate.
++        """
++        return self._copyName('subject')
++
++
++
++def _handleattrhelper(Class, transport, methodName):
++    """
++    (private) Helper for L{Certificate.peerFromTransport} and
++    L{Certificate.hostFromTransport} which checks for incompatible handle types
++    and null certificates and raises the appropriate exception or returns the
++    appropriate certificate object.
++    """
++    method = getattr(transport.getHandle(),
++                     "get_%s_certificate" % (methodName,), None)
++    if method is None:
++        raise CertificateError(
++            "non-TLS transport %r did not have %s certificate" % (transport, methodName))
++    cert = method()
++    if cert is None:
++        raise CertificateError(
++            "TLS transport %r did not have %s certificate" % (transport, methodName))
++    return Class(cert)
++
++
++class Certificate(CertBase):
++    """
++    An x509 certificate.
++    """
++    def __repr__(self):
++        return '<%s Subject=%s Issuer=%s>' % (self.__class__.__name__,
++                                              self.getSubject().commonName,
++                                              self.getIssuer().commonName)
++
++    def __eq__(self, other):
++        if isinstance(other, Certificate):
++            return self.dump() == other.dump()
++        return False
++
++
++    def __ne__(self, other):
++        return not self.__eq__(other)
++
++
++    def load(Class, requestData, format=crypto.FILETYPE_ASN1, args=()):
++        """
++        Load a certificate from an ASN.1- or PEM-format string.
++
++        @rtype: C{Class}
++        """
++        return Class(crypto.load_certificate(format, requestData), *args)
++    load = classmethod(load)
++    _load = load
++
++
++    def dumpPEM(self):
++        """
++        Dump this certificate to a PEM-format data string.
++
++        @rtype: C{str}
++        """
++        return self.dump(crypto.FILETYPE_PEM)
++
++
++    def loadPEM(Class, data):
++        """
++        Load a certificate from a PEM-format data string.
++
++        @rtype: C{Class}
++        """
++        return Class.load(data, crypto.FILETYPE_PEM)
++    loadPEM = classmethod(loadPEM)
++
++
++    def peerFromTransport(Class, transport):
++        """
++        Get the certificate for the remote end of the given transport.
++
++        @type: L{ISystemHandle}
++        @rtype: C{Class}
++
++        @raise: L{CertificateError}, if the given transport does not have a peer
++        certificate.
++        """
++        return _handleattrhelper(Class, transport, 'peer')
++    peerFromTransport = classmethod(peerFromTransport)
++
++
++    def hostFromTransport(Class, transport):
++        """
++        Get the certificate for the local end of the given transport.
++
++        @param transport: an L{ISystemHandle} provider; the transport we will
++
++        @rtype: C{Class}
++
++        @raise: L{CertificateError}, if the given transport does not have a host
++        certificate.
++        """
++        return _handleattrhelper(Class, transport, 'host')
++    hostFromTransport = classmethod(hostFromTransport)
++
++
++    def getPublicKey(self):
++        """
++        Get the public key for this certificate.
++
++        @rtype: L{PublicKey}
++        """
++        return PublicKey(self.original.get_pubkey())
++
++
++    def dump(self, format=crypto.FILETYPE_ASN1):
++        return crypto.dump_certificate(format, self.original)
++
++
++    def serialNumber(self):
++        """
++        Retrieve the serial number of this certificate.
++
++        @rtype: C{int}
++        """
++        return self.original.get_serial_number()
++
++
++    def digest(self, method='md5'):
++        """
++        Return a digest hash of this certificate using the specified hash
++        algorithm.
++
++        @param method: One of C{'md5'} or C{'sha'}.
++        @rtype: C{str}
++        """
++        return self.original.digest(method)
++
++
++    def _inspect(self):
++        return '\n'.join(['Certificate For Subject:',
++                          self.getSubject().inspect(),
++                          '\nIssuer:',
++                          self.getIssuer().inspect(),
++                          '\nSerial Number: %d' % self.serialNumber(),
++                          'Digest: %s' % self.digest()])
++
++
++    def inspect(self):
++        """
++        Return a multi-line, human-readable representation of this
++        Certificate, including information about the subject, issuer, and
++        public key.
++        """
++        return '\n'.join((self._inspect(), self.getPublicKey().inspect()))
++
++
++    def getIssuer(self):
++        """
++        Retrieve the issuer of this certificate.
++
++        @rtype: L{DistinguishedName}
++        @return: A copy of the issuer of this certificate.
++        """
++        return self._copyName('issuer')
++
++
++    def options(self, *authorities):
++        raise NotImplementedError('Possible, but doubtful we need this yet')
++
++
++
++class CertificateRequest(CertBase):
++    """
++    An x509 certificate request.
++
++    Certificate requests are given to certificate authorities to be signed and
++    returned resulting in an actual certificate.
++    """
++    def load(Class, requestData, requestFormat=crypto.FILETYPE_ASN1):
++        req = crypto.load_certificate_request(requestFormat, requestData)
++        dn = DistinguishedName()
++        dn._copyFrom(req.get_subject())
++        if not req.verify(req.get_pubkey()):
++            raise VerifyError("Can't verify that request for %r is self-signed." % (dn,))
++        return Class(req)
++    load = classmethod(load)
++
++
++    def dump(self, format=crypto.FILETYPE_ASN1):
++        return crypto.dump_certificate_request(format, self.original)
++
++
++
++class PrivateCertificate(Certificate):
++    """
++    An x509 certificate and private key.
++    """
++    def __repr__(self):
++        return Certificate.__repr__(self) + ' with ' + repr(self.privateKey)
++
++
++    def _setPrivateKey(self, privateKey):
++        if not privateKey.matches(self.getPublicKey()):
++            raise VerifyError(
++                "Sanity check failed: Your certificate was not properly signed.")
++        self.privateKey = privateKey
++        return self
++
++
++    def newCertificate(self, newCertData, format=crypto.FILETYPE_ASN1):
++        """
++        Create a new L{PrivateCertificate} from the given certificate data and
++        this instance's private key.
++        """
++        return self.load(newCertData, self.privateKey, format)
++
++
++    def load(Class, data, privateKey, format=crypto.FILETYPE_ASN1):
++        return Class._load(data, format)._setPrivateKey(privateKey)
++    load = classmethod(load)
++
++
++    def inspect(self):
++        return '\n'.join([Certificate._inspect(self),
++                          self.privateKey.inspect()])
++
++
++    def dumpPEM(self):
++        """
++        Dump both public and private parts of a private certificate to
++        PEM-format data.
++        """
++        return self.dump(crypto.FILETYPE_PEM) + self.privateKey.dump(crypto.FILETYPE_PEM)
++
++
++    def loadPEM(Class, data):
++        """
++        Load both private and public parts of a private certificate from a
++        chunk of PEM-format data.
++        """
++        return Class.load(data, KeyPair.load(data, crypto.FILETYPE_PEM),
++                          crypto.FILETYPE_PEM)
++    loadPEM = classmethod(loadPEM)
++
++
++    def fromCertificateAndKeyPair(Class, certificateInstance, privateKey):
++        privcert = Class(certificateInstance.original)
++        return privcert._setPrivateKey(privateKey)
++    fromCertificateAndKeyPair = classmethod(fromCertificateAndKeyPair)
++
++
++    def options(self, *authorities):
++        options = dict(privateKey=self.privateKey.original,
++                       certificate=self.original)
++        if authorities:
++            options.update(dict(verify=True,
++                                requireCertificate=True,
++                                caCerts=[auth.original for auth in authorities]))
++        return OpenSSLCertificateOptions(**options)
++
++
++    def certificateRequest(self, format=crypto.FILETYPE_ASN1,
++                           digestAlgorithm='md5'):
++        return self.privateKey.certificateRequest(
++            self.getSubject(),
++            format,
++            digestAlgorithm)
++
++
++    def signCertificateRequest(self,
++                               requestData,
++                               verifyDNCallback,
++                               serialNumber,
++                               requestFormat=crypto.FILETYPE_ASN1,
++                               certificateFormat=crypto.FILETYPE_ASN1):
++        issuer = self.getSubject()
++        return self.privateKey.signCertificateRequest(
++            issuer,
++            requestData,
++            verifyDNCallback,
++            serialNumber,
++            requestFormat,
++            certificateFormat)
++
++
++    def signRequestObject(self, certificateRequest, serialNumber,
++                          secondsToExpiry=60 * 60 * 24 * 365, # One year
++                          digestAlgorithm='md5'):
++        return self.privateKey.signRequestObject(self.getSubject(),
++                                                 certificateRequest,
++                                                 serialNumber,
++                                                 secondsToExpiry,
++                                                 digestAlgorithm)
++
++
++class PublicKey:
++    def __init__(self, osslpkey):
++        self.original = osslpkey
++        req1 = crypto.X509Req()
++        req1.set_pubkey(osslpkey)
++        self._emptyReq = crypto.dump_certificate_request(crypto.FILETYPE_ASN1, req1)
++
++
++    def matches(self, otherKey):
++        return self._emptyReq == otherKey._emptyReq
++
++
++    # XXX This could be a useful method, but sometimes it triggers a segfault,
++    # so we'll steer clear for now.
++#     def verifyCertificate(self, certificate):
++#         """
++#         returns None, or raises a VerifyError exception if the certificate
++#         could not be verified.
++#         """
++#         if not certificate.original.verify(self.original):
++#             raise VerifyError("We didn't sign that certificate.")
++
++    def __repr__(self):
++        return '<%s %s>' % (self.__class__.__name__, self.keyHash())
++
++
++    def keyHash(self):
++        """
++        MD5 hex digest of signature on an empty certificate request with this
++        key.
++        """
++        return md5.md5(self._emptyReq).hexdigest()
++
++
++    def inspect(self):
++        return 'Public Key with Hash: %s' % (self.keyHash(),)
++
++
++
++class KeyPair(PublicKey):
++
++    def load(Class, data, format=crypto.FILETYPE_ASN1):
++        return Class(crypto.load_privatekey(format, data))
++    load = classmethod(load)
++
++
++    def dump(self, format=crypto.FILETYPE_ASN1):
++        return crypto.dump_privatekey(format, self.original)
++
++
++    def __getstate__(self):
++        return self.dump()
++
++
++    def __setstate__(self, state):
++        self.__init__(crypto.load_privatekey(crypto.FILETYPE_ASN1, state))
++
++
++    def inspect(self):
++        t = self.original.type()
++        if t == crypto.TYPE_RSA:
++            ts = 'RSA'
++        elif t == crypto.TYPE_DSA:
++            ts = 'DSA'
++        else:
++            ts = '(Unknown Type!)'
++        L = (self.original.bits(), ts, self.keyHash())
++        return '%s-bit %s Key Pair with Hash: %s' % L
++
++
++    def generate(Class, kind=crypto.TYPE_RSA, size=1024):
++        pkey = crypto.PKey()
++        pkey.generate_key(kind, size)
++        return Class(pkey)
++
++
++    def newCertificate(self, newCertData, format=crypto.FILETYPE_ASN1):
++        return PrivateCertificate.load(newCertData, self, format)
++    generate = classmethod(generate)
++
++
++    def requestObject(self, distinguishedName, digestAlgorithm='md5'):
++        req = crypto.X509Req()
++        req.set_pubkey(self.original)
++        distinguishedName._copyInto(req.get_subject())
++        req.sign(self.original, digestAlgorithm)
++        return CertificateRequest(req)
++
++
++    def certificateRequest(self, distinguishedName,
++                           format=crypto.FILETYPE_ASN1,
++                           digestAlgorithm='md5'):
++        """Create a certificate request signed with this key.
++
++        @return: a string, formatted according to the 'format' argument.
++        """
++        return self.requestObject(distinguishedName, digestAlgorithm).dump(format)
++
++
++    def signCertificateRequest(self,
++                               issuerDistinguishedName,
++                               requestData,
++                               verifyDNCallback,
++                               serialNumber,
++                               requestFormat=crypto.FILETYPE_ASN1,
++                               certificateFormat=crypto.FILETYPE_ASN1,
++                               secondsToExpiry=60 * 60 * 24 * 365, # One year
++                               digestAlgorithm='md5'):
++        """
++        Given a blob of certificate request data and a certificate authority's
++        DistinguishedName, return a blob of signed certificate data.
++
++        If verifyDNCallback returns a Deferred, I will return a Deferred which
++        fires the data when that Deferred has completed.
++        """
++        hlreq = CertificateRequest.load(requestData, requestFormat)
++
++        dn = hlreq.getSubject()
++        vval = verifyDNCallback(dn)
++
++        def verified(value):
++            if not value:
++                raise VerifyError("DN callback %r rejected request DN %r" % (verifyDNCallback, dn))
++            return self.signRequestObject(issuerDistinguishedName, hlreq,
++                                          serialNumber, secondsToExpiry, digestAlgorithm).dump(certificateFormat)
++
++        if isinstance(vval, Deferred):
++            return vval.addCallback(verified)
++        else:
++            return verified(vval)
++
++
++    def signRequestObject(self,
++                          issuerDistinguishedName,
++                          requestObject,
++                          serialNumber,
++                          secondsToExpiry=60 * 60 * 24 * 365, # One year
++                          digestAlgorithm='md5'):
++        """
++        Sign a CertificateRequest instance, returning a Certificate instance.
++        """
++        req = requestObject.original
++        dn = requestObject.getSubject()
++        cert = crypto.X509()
++        issuerDistinguishedName._copyInto(cert.get_issuer())
++        cert.set_subject(req.get_subject())
++        cert.set_pubkey(req.get_pubkey())
++        cert.gmtime_adj_notBefore(0)
++        cert.gmtime_adj_notAfter(secondsToExpiry)
++        cert.set_serial_number(serialNumber)
++        cert.sign(self.original, digestAlgorithm)
++        return Certificate(cert)
++
++
++    def selfSignedCert(self, serialNumber, **kw):
++        dn = DN(**kw)
++        return PrivateCertificate.fromCertificateAndKeyPair(
++            self.signRequestObject(dn, self.requestObject(dn), serialNumber),
++            self)
++
++
++
++class OpenSSLCertificateOptions(object):
++    """
++    A factory for SSL context objects for both SSL servers and clients.
++    """
++
++    _context = None
++    # Older versions of PyOpenSSL didn't provide OP_ALL.  Fudge it here, just in case.
++    _OP_ALL = getattr(SSL, 'OP_ALL', 0x0000FFFF)
++    # OP_NO_TICKET is not (yet) exposed by PyOpenSSL
++    _OP_NO_TICKET = 0x00004000
++
++    method = SSL.TLSv1_METHOD
++
++    def __init__(self,
++                 privateKey=None,
++                 certificate=None,
++                 method=None,
++                 verify=False,
++                 caCerts=None,
++                 verifyDepth=9,
++                 requireCertificate=True,
++                 verifyOnce=True,
++                 enableSingleUseKeys=True,
++                 enableSessions=True,
++                 fixBrokenPeers=False,
++                 enableSessionTickets=False):
++        """
++        Create an OpenSSL context SSL connection context factory.
++
++        @param privateKey: A PKey object holding the private key.
++
++        @param certificate: An X509 object holding the certificate.
++
++        @param method: The SSL protocol to use, one of SSLv23_METHOD,
++        SSLv2_METHOD, SSLv3_METHOD, TLSv1_METHOD.  Defaults to TLSv1_METHOD.
++
++        @param verify: If True, verify certificates received from the peer and
++        fail the handshake if verification fails.  Otherwise, allow anonymous
++        sessions and sessions with certificates which fail validation.  By
++        default this is False.
++
++        @param caCerts: List of certificate authority certificates to
++        send to the client when requesting a certificate.  Only used if verify
++        is True, and if verify is True, either this must be specified or
++        caCertsFile must be given.  Since verify is False by default,
++        this is None by default.
++
++        @param verifyDepth: Depth in certificate chain down to which to verify.
++        If unspecified, use the underlying default (9).
++
++        @param requireCertificate: If True, do not allow anonymous sessions.
++
++        @param verifyOnce: If True, do not re-verify the certificate
++        on session resumption.
++
++        @param enableSingleUseKeys: If True, generate a new key whenever
++        ephemeral DH parameters are used to prevent small subgroup attacks.
++
++        @param enableSessions: If True, set a session ID on each context.  This
++        allows a shortened handshake to be used when a known client reconnects.
++
++        @param fixBrokenPeers: If True, enable various non-spec protocol fixes
++        for broken SSL implementations.  This should be entirely safe,
++        according to the OpenSSL documentation, but YMMV.  This option is now
++        off by default, because it causes problems with connections between
++        peers using OpenSSL 0.9.8a.
++
++        @param enableSessionTickets: If True, enable session ticket extension
++        for session resumption per RFC 5077. Note there is no support for
++        controlling session tickets. This option is off by default, as some
++        server implementations don't correctly process incoming empty session
++        ticket extensions in the hello.
++        """
++
++        assert (privateKey is None) == (certificate is None), "Specify neither or both of privateKey and certificate"
++        self.privateKey = privateKey
++        self.certificate = certificate
++        if method is not None:
++            self.method = method
++
++        self.verify = verify
++        assert ((verify and caCerts) or
++                (not verify)), "Specify client CA certificate information if and only if enabling certificate verification"
++
++        self.caCerts = caCerts
++        self.verifyDepth = verifyDepth
++        self.requireCertificate = requireCertificate
++        self.verifyOnce = verifyOnce
++        self.enableSingleUseKeys = enableSingleUseKeys
++        self.enableSessions = enableSessions
++        self.fixBrokenPeers = fixBrokenPeers
++        self.enableSessionTickets = enableSessionTickets
++
++
++    def __getstate__(self):
++        d = self.__dict__.copy()
++        try:
++            del d['_context']
++        except KeyError:
++            pass
++        return d
++
++
++    def __setstate__(self, state):
++        self.__dict__ = state
++
++
++    def getContext(self):
++        """Return a SSL.Context object.
++        """
++        if self._context is None:
++            self._context = self._makeContext()
++        return self._context
++
++
++    def _makeContext(self):
++        ctx = SSL.Context(self.method)
++
++        if self.certificate is not None and self.privateKey is not None:
++            ctx.use_certificate(self.certificate)
++            ctx.use_privatekey(self.privateKey)
++            # Sanity check
++            ctx.check_privatekey()
++
++        verifyFlags = SSL.VERIFY_NONE
++        if self.verify:
++            verifyFlags = SSL.VERIFY_PEER
++            if self.requireCertificate:
++                verifyFlags |= SSL.VERIFY_FAIL_IF_NO_PEER_CERT
++            if self.verifyOnce:
++                verifyFlags |= SSL.VERIFY_CLIENT_ONCE
++            if self.caCerts:
++                store = ctx.get_cert_store()
++                for cert in self.caCerts:
++                    store.add_cert(cert)
++
++        # It'd be nice if pyOpenSSL let us pass None here for this behavior (as
++        # the underlying OpenSSL API call allows NULL to be passed).  It
++        # doesn't, so we'll supply a function which does the same thing.
++        def _verifyCallback(conn, cert, errno, depth, preverify_ok):
++            return preverify_ok
++        ctx.set_verify(verifyFlags, _verifyCallback)
++
++        if self.verifyDepth is not None:
++            ctx.set_verify_depth(self.verifyDepth)
++
++        if self.enableSingleUseKeys:
++            ctx.set_options(SSL.OP_SINGLE_DH_USE)
++
++        if self.fixBrokenPeers:
++            ctx.set_options(self._OP_ALL)
++
++        if self.enableSessions:
++            sessionName = md5.md5("%s-%d" % (reflect.qual(self.__class__), _sessionCounter())).hexdigest()
++            ctx.set_session_id(sessionName)
++
++        if not self.enableSessionTickets:
++            ctx.set_options(self._OP_NO_TICKET)
++
++        return ctx
+diff -Naur TwistedCore-8.2.0/twisted/internet/_sslverify.py.rej TwistedCore-8.2.0.patched/twisted/internet/_sslverify.py.rej
+--- TwistedCore-8.2.0/twisted/internet/_sslverify.py.rej	1970-01-01 01:00:00.000000000 +0100
++++ TwistedCore-8.2.0.patched/twisted/internet/_sslverify.py.rej	2010-04-20 09:43:18.000000000 +0200
+@@ -0,0 +1,18 @@
++--- twisted/internet/_sslverify.py	(revision 24403)
+++++ twisted/internet/_sslverify.py	(revision 25457)
++@@ -1,9 +1,12 @@
++ # -*- test-case-name: twisted.test.test_sslverify -*-
++-# Copyright 2005 Divmod, Inc.  See LICENSE file for details
++-
++-import itertools, md5
+++# Copyright (c) 2005 Divmod, Inc.
+++# Copyright (c) 2008 Twisted Matrix Laboratories.
+++# See LICENSE for details.
+++
+++import itertools
++ from OpenSSL import SSL, crypto
++ 
++ from twisted.python import reflect, util
+++from twisted.python.hashlib import md5
++ from twisted.internet.defer import Deferred
++ from twisted.internet.error import VerifyError, CertificateError
+diff -Naur TwistedCore-8.2.0/twisted/persisted/sob.py TwistedCore-8.2.0.patched/twisted/persisted/sob.py
+--- TwistedCore-8.2.0/twisted/persisted/sob.py	2008-07-29 22:13:54.000000000 +0200
++++ TwistedCore-8.2.0.patched/twisted/persisted/sob.py	2010-04-20 09:43:17.000000000 +0200
+@@ -1,5 +1,5 @@
+ # -*- test-case-name: twisted.test.test_sob -*-
+-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
++# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
+ # See LICENSE for details.
+ 
+ #
+@@ -9,7 +9,7 @@
+ Maintainer: Moshe Zadka
+ """
+ 
+-import os, md5, sys
++import os, sys
+ try:
+     import cPickle as pickle
+ except ImportError:
+@@ -19,6 +19,7 @@
+ except ImportError:
+     import StringIO
+ from twisted.python import log, runtime
++from twisted.python.hashlib import md5
+ from twisted.persisted import styles
+ from zope.interface import implements, Interface
+ 
+@@ -31,11 +32,11 @@
+     leftover = len(data) % cipher.block_size
+     if leftover:
+         data += ' '*(cipher.block_size - leftover)
+-    return cipher.new(md5.new(passphrase).digest()[:16]).encrypt(data)
++    return cipher.new(md5(passphrase).digest()[:16]).encrypt(data)
+ 
+ def _decrypt(passphrase, data):
+     from Crypto.Cipher import AES
+-    return AES.new(md5.new(passphrase).digest()[:16]).decrypt(data)
++    return AES.new(md5(passphrase).digest()[:16]).decrypt(data)
+ 
+ 
+ class IPersistable(Interface):
+diff -Naur TwistedCore-8.2.0/twisted/protocols/sip.py TwistedCore-8.2.0.patched/twisted/protocols/sip.py
 --- TwistedCore-8.2.0/twisted/protocols/sip.py	2006-07-01 18:08:17.000000000 +0200
-+++ TwistedCore-8.2.0.patched/twisted/protocols/sip.py	2010-04-15 13:02:41.000000000 +0200
++++ TwistedCore-8.2.0.patched/twisted/protocols/sip.py	2010-04-20 09:43:01.000000000 +0200
 @@ -1,6 +1,6 @@
  # -*- test-case-name: twisted.test.test_sip -*-
  
@@ -95,9 +1030,9 @@ diff -aur TwistedCore-8.2.0/twisted/prot
      m.update(HA1)
      m.update(":")
      m.update(pszNonce)
-diff -aur TwistedCore-8.2.0/twisted/python/filepath.py TwistedCore-8.2.0.patched/twisted/python/filepath.py
+diff -Naur TwistedCore-8.2.0/twisted/python/filepath.py TwistedCore-8.2.0.patched/twisted/python/filepath.py
 --- TwistedCore-8.2.0/twisted/python/filepath.py	2008-07-08 14:17:24.000000000 +0200
-+++ TwistedCore-8.2.0.patched/twisted/python/filepath.py	2010-04-15 13:02:41.000000000 +0200
++++ TwistedCore-8.2.0.patched/twisted/python/filepath.py	2010-04-20 09:43:01.000000000 +0200
 @@ -9,7 +9,6 @@
  import os
  import errno
@@ -123,10 +1058,37 @@ diff -aur TwistedCore-8.2.0/twisted/pyth
  
  
  
-Only in TwistedCore-8.2.0.patched/twisted/python: hashlib.py
-diff -aur TwistedCore-8.2.0/twisted/python/otp.py TwistedCore-8.2.0.patched/twisted/python/otp.py
+diff -Naur TwistedCore-8.2.0/twisted/python/hashlib.py TwistedCore-8.2.0.patched/twisted/python/hashlib.py
+--- TwistedCore-8.2.0/twisted/python/hashlib.py	1970-01-01 01:00:00.000000000 +0100
++++ TwistedCore-8.2.0.patched/twisted/python/hashlib.py	2010-04-20 09:43:01.000000000 +0200
+@@ -0,0 +1,24 @@
++# -*- test-case-name: twisted.python.test.test_hashlib -*-
++# Copyright (c) 2008 Twisted Matrix Laboratories.
++# See LICENSE for details.
++
++"""
++L{twisted.python.hashlib} presents a subset of the interface provided by
++U{hashlib<http://docs.python.org/library/hashlib.html>}.  The subset is the
++interface required by various parts of Twisted.  This allows application code
++to transparently use APIs which existed before C{hashlib} was introduced or to
++use C{hashlib} if it is available.
++"""
++
++
++try:
++    _hashlib = __import__("hashlib")
++except ImportError:
++    from md5 import md5
++    from sha import sha as sha1
++else:
++    md5  = _hashlib.md5
++    sha1 = _hashlib.sha1
++
++
++__all__ = ["md5", "sha1"]
+diff -Naur TwistedCore-8.2.0/twisted/python/otp.py TwistedCore-8.2.0.patched/twisted/python/otp.py
 --- TwistedCore-8.2.0/twisted/python/otp.py	2004-08-25 10:36:30.000000000 +0200
-+++ TwistedCore-8.2.0.patched/twisted/python/otp.py	2010-04-15 13:02:41.000000000 +0200
++++ TwistedCore-8.2.0.patched/twisted/python/otp.py	2010-04-20 09:43:01.000000000 +0200
 @@ -1,7 +1,9 @@
 -# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
 +# -*- test-case-name: twisted.python.test.test_otp -*-
@@ -268,10 +1230,103 @@ diff -aur TwistedCore-8.2.0/twisted/pyth
  "YARD",  "YARN",  "YAWL",  "YAWN",  "YEAH",  "YEAR",  "YELL",  "YOGA",
  "YOKE"]
 -
-Only in TwistedCore-8.2.0.patched/twisted/python/test: test_hashlib.py
-diff -aur TwistedCore-8.2.0/twisted/python/test/test_zipstream.py TwistedCore-8.2.0.patched/twisted/python/test/test_zipstream.py
+diff -Naur TwistedCore-8.2.0/twisted/python/test/test_hashlib.py TwistedCore-8.2.0.patched/twisted/python/test/test_hashlib.py
+--- TwistedCore-8.2.0/twisted/python/test/test_hashlib.py	1970-01-01 01:00:00.000000000 +0100
++++ TwistedCore-8.2.0.patched/twisted/python/test/test_hashlib.py	2010-04-20 09:43:01.000000000 +0200
+@@ -0,0 +1,90 @@
++# Copyright (c) 2008 Twisted Matrix Laboratories.
++# See LICENSE for details.
++
++"""
++Tests for L{twisted.python.hashlib}
++"""
++
++from twisted.trial.unittest import TestCase
++
++from twisted.python.hashlib import md5, sha1
++
++
++class HashObjectTests(TestCase):
++    """
++    Tests for the hash object APIs presented by L{hashlib}, C{md5} and C{sha1}.
++    """
++    def test_md5(self):
++        """
++        L{hashlib.md5} returns an object which can be used to compute an MD5
++        hash as defined by U{RFC 1321<http://www.ietf.org/rfc/rfc1321.txt>}.
++        """
++        # Test the result using values from section A.5 of the RFC.
++        self.assertEqual(
++            md5().hexdigest(), "d41d8cd98f00b204e9800998ecf8427e")
++        self.assertEqual(
++            md5("a").hexdigest(), "0cc175b9c0f1b6a831c399e269772661")
++        self.assertEqual(
++            md5("abc").hexdigest(), "900150983cd24fb0d6963f7d28e17f72")
++        self.assertEqual(
++            md5("message digest").hexdigest(),
++            "f96b697d7cb7938d525a2f31aaf161d0")
++        self.assertEqual(
++            md5("abcdefghijklmnopqrstuvwxyz").hexdigest(),
++            "c3fcd3d76192e4007dfb496cca67e13b")
++        self.assertEqual(
++            md5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
++                "0123456789").hexdigest(),
++            "d174ab98d277d9f5a5611c2c9f419d9f")
++        self.assertEqual(
++            md5("1234567890123456789012345678901234567890123456789012345678901"
++                "2345678901234567890").hexdigest(),
++            "57edf4a22be3c955ac49da2e2107b67a")
++
++        # It should have digest and update methods, too.
++        self.assertEqual(
++            md5().digest().encode('hex'),
++            "d41d8cd98f00b204e9800998ecf8427e")
++        hash = md5()
++        hash.update("a")
++        self.assertEqual(
++            hash.digest().encode('hex'),
++            "0cc175b9c0f1b6a831c399e269772661")
++
++        # Instances of it should have a digest_size attribute
++        self.assertEqual(md5().digest_size, 16)
++
++
++    def test_sha1(self):
++        """
++        L{hashlib.sha1} returns an object which can be used to compute a SHA1
++        hash as defined by U{RFC 3174<http://tools.ietf.org/rfc/rfc3174.txt>}.
++        """
++        def format(s):
++            return ''.join(s.split()).lower()
++        # Test the result using values from section 7.3 of the RFC.
++        self.assertEqual(
++            sha1("abc").hexdigest(),
++            format(
++                "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D"))
++        self.assertEqual(
++            sha1("abcdbcdecdefdefgefghfghighijhi"
++                 "jkijkljklmklmnlmnomnopnopq").hexdigest(),
++            format(
++                "84 98 3E 44 1C 3B D2 6E BA AE 4A A1 F9 51 29 E5 E5 46 70 F1"))
++
++        # It should have digest and update methods, too.
++        self.assertEqual(
++            sha1("abc").digest().encode('hex'),
++            format(
++                "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D"))
++        hash = sha1()
++        hash.update("abc")
++        self.assertEqual(
++            hash.digest().encode('hex'),
++            format(
++                "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D"))
++
++        # Instances of it should have a digest_size attribute.
++        self.assertEqual(
++            sha1().digest_size, 20)
+diff -Naur TwistedCore-8.2.0/twisted/python/test/test_zipstream.py TwistedCore-8.2.0.patched/twisted/python/test/test_zipstream.py
 --- TwistedCore-8.2.0/twisted/python/test/test_zipstream.py	2008-02-07 09:23:49.000000000 +0100
-+++ TwistedCore-8.2.0.patched/twisted/python/test/test_zipstream.py	2010-04-15 13:02:41.000000000 +0200
++++ TwistedCore-8.2.0.patched/twisted/python/test/test_zipstream.py	2010-04-20 09:43:01.000000000 +0200
 @@ -6,10 +6,10 @@
  """
  import sys
@@ -302,9 +1357,9 @@ diff -aur TwistedCore-8.2.0/twisted/pyth
              tempdir.child("zipstreamjunk").open().read()).hexdigest()
          self.assertEqual(newmd5, junkmd5)
  
-diff -aur TwistedCore-8.2.0/twisted/spread/pb.py TwistedCore-8.2.0.patched/twisted/spread/pb.py
+diff -Naur TwistedCore-8.2.0/twisted/spread/pb.py TwistedCore-8.2.0.patched/twisted/spread/pb.py
 --- TwistedCore-8.2.0/twisted/spread/pb.py	2008-07-29 22:13:54.000000000 +0200
-+++ TwistedCore-8.2.0.patched/twisted/spread/pb.py	2010-04-15 13:02:41.000000000 +0200
++++ TwistedCore-8.2.0.patched/twisted/spread/pb.py	2010-04-20 09:43:18.000000000 +0200
 @@ -27,7 +27,6 @@
  @author: Glyph Lefkowitz
  """
@@ -358,9 +1413,82 @@ diff -aur TwistedCore-8.2.0/twisted/spre
          md.update(md5Password)
          md.update(self.challenge)
          correct = md.digest()
-diff -aur TwistedCore-8.2.0/twisted/trial/test/test_loader.py TwistedCore-8.2.0.patched/twisted/trial/test/test_loader.py
+diff -Naur TwistedCore-8.2.0/twisted/test/test_newcred.py TwistedCore-8.2.0.patched/twisted/test/test_newcred.py
+--- TwistedCore-8.2.0/twisted/test/test_newcred.py	2007-07-28 14:44:09.000000000 +0200
++++ TwistedCore-8.2.0.patched/twisted/test/test_newcred.py	2010-04-20 09:43:18.000000000 +0200
+@@ -1,8 +1,8 @@
+-# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
++# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
+ # See LICENSE for details.
+ 
+ """
+-Now with 30% more starch.
++Tests for L{twisted.cred}, now with 30% more starch.
+ """
+ 
+ 
+@@ -10,7 +10,7 @@
+ from zope.interface import implements, Interface
+ 
+ from twisted.trial import unittest
+-from twisted.cred import portal, checkers, credentials, error
++from twisted.cred import portal, checkers, credentials, error, util
+ from twisted.python import components
+ from twisted.internet import defer
+ from twisted.internet.defer import deferredGenerator as dG, waitForDeferred as wFD
+@@ -27,6 +27,49 @@
+ else:
+     from twisted.cred import pamauth
+ 
++
++class DeprecatedUtilTests(unittest.TestCase):
++    """
++    Tests for the deprecation of the functions in L{twisted.cred.util}.
++    """
++    def test_respond(self):
++        """
++        L{respond} applies a particular hashing to a challenge and a password
++        and returns the result.  It is deprecated and calling it emits a
++        deprecation warning.
++        """
++        # Use some values and test against the known correct output.
++        self.assertEqual(
++            util.respond('foo', 'bar').encode('hex'),
++            'ebe4a2902532198cafaa223fb5ac0f20')
++
++        warnings = self.flushWarnings(offendingFunctions=[self.test_respond])
++        self.assertEqual(
++            warnings[0]['message'],
++            'twisted.cred.util.respond is deprecated since Twisted 8.3.')
++        self.assertEqual(
++            warnings[0]['category'],
++            PendingDeprecationWarning)
++        self.assertEqual(len(warnings), 1)
++
++
++    def test_challenge(self):
++        """
++        L{challenge} returns a different string each time it is called.
++        """
++        self.assertNotEqual(util.challenge(), util.challenge())
++        warnings = self.flushWarnings(offendingFunctions=[self.test_challenge])
++        for w in warnings:
++            self.assertEqual(
++                w['message'],
++                'twisted.cred.util.challenge is deprecated since Twisted 8.3.')
++            self.assertEqual(
++                w['category'],
++                PendingDeprecationWarning)
++        self.assertEqual(len(warnings), 2)
++
++
++
+ class ITestable(Interface):
+     pass
+ 
+diff -Naur TwistedCore-8.2.0/twisted/trial/test/test_loader.py TwistedCore-8.2.0.patched/twisted/trial/test/test_loader.py
 --- TwistedCore-8.2.0/twisted/trial/test/test_loader.py	2008-09-01 18:42:51.000000000 +0200
-+++ TwistedCore-8.2.0.patched/twisted/trial/test/test_loader.py	2010-04-15 13:02:41.000000000 +0200
++++ TwistedCore-8.2.0.patched/twisted/trial/test/test_loader.py	2010-04-20 09:43:18.000000000 +0200
 @@ -5,12 +5,12 @@
  Tests for loading tests by name.
  """
@@ -384,32 +1512,31 @@ diff -aur TwistedCore-8.2.0/twisted/tria
              return d
          self.loadSortedPackages(sillySorter)
  
-
-diff -Naur TwistedCore-8.2.0/twisted/python/hashlib.py TwistedCore-8.2.0.patched/twisted/python/hashlib.py
---- TwistedCore-8.2.0/twisted/python/hashlib.py	1970-01-01 01:00:00.000000000 +0100
-+++ TwistedCore-8.2.0.patched/twisted/python/hashlib.py	2010-04-15 13:02:41.000000000 +0200
+diff -Naur TwistedCore-8.2.0/twisted/words/test/test_oscar.py TwistedCore-8.2.0.patched/twisted/words/test/test_oscar.py
+--- TwistedCore-8.2.0/twisted/words/test/test_oscar.py	1970-01-01 01:00:00.000000000 +0100
++++ TwistedCore-8.2.0.patched/twisted/words/test/test_oscar.py	2010-04-20 09:43:16.000000000 +0200
 @@ -0,0 +1,24 @@
-+# -*- test-case-name: twisted.python.test.test_hashlib -*-
 +# Copyright (c) 2008 Twisted Matrix Laboratories.
 +# See LICENSE for details.
 +
 +"""
-+L{twisted.python.hashlib} presents a subset of the interface provided by
-+U{hashlib<http://docs.python.org/library/hashlib.html>}.  The subset is the
-+interface required by various parts of Twisted.  This allows application code
-+to transparently use APIs which existed before C{hashlib} was introduced or to
-+use C{hashlib} if it is available.
++Tests for L{twisted.words.protocols.oscar}.
 +"""
 +
++from twisted.trial.unittest import TestCase
 +
-+try:
-+    _hashlib = __import__("hashlib")
-+except ImportError:
-+    from md5 import md5
-+    from sha import sha as sha1
-+else:
-+    md5  = _hashlib.md5
-+    sha1 = _hashlib.sha1
++from twisted.words.protocols.oscar import encryptPasswordMD5
 +
 +
-+__all__ = ["md5", "sha1"]
++class PasswordTests(TestCase):
++    """
++    Tests for L{encryptPasswordMD5}.
++    """
++    def test_encryptPasswordMD5(self):
++        """
++        L{encryptPasswordMD5} hashes the given password and key and returns a
++        string suitable to use to authenticate against an OSCAR server.
++        """
++        self.assertEqual(
++            encryptPasswordMD5('foo', 'bar').encode('hex'),
++            'd73475c370a7b18c6c20386bcf1339f2')


Index: python-twisted-core.spec
===================================================================
RCS file: /cvs/pkgs/rpms/python-twisted-core/F-13/python-twisted-core.spec,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -p -r1.16 -r1.17
--- python-twisted-core.spec	18 Apr 2010 10:42:37 -0000	1.16
+++ python-twisted-core.spec	20 Apr 2010 07:53:01 -0000	1.17
@@ -3,7 +3,7 @@
 
 Name:           %{python}-twisted-core
 Version:        8.2.0
-Release:        5%{?dist}
+Release:        6%{?dist}
 Summary:        Asynchronous networking framework written in Python
 Group:          Development/Libraries
 License:        MIT
@@ -194,6 +194,11 @@ fi
 %{_datadir}/zsh/site-functions/_twisted_zsh_stub
 
 %changelog
+* Tue Apr 20 2010 Thomas Vander Stichele <thomas at apestaart dot org>
+- 8.2.0-6
+- Once more, fishing out all the parts of the patch that affect TwistedCore
+  but none of the other modules.
+
 * Sun Apr 18 2010 Thomas Vander Stichele <thomas at apestaart dot org>
 - 8.2.0-5
 - include the important missing hashlib.py to fix #583304



More information about the scm-commits mailing list