File Twisted-8.2.0-deprecations.patch of Package python-twisted
--- twisted/conch/scripts/ckeygen.py
+++ twisted/conch/scripts/ckeygen.py
@@ -1,16 +1,12 @@
-# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
+# -*- test-case-name: twisted.conch.test.test_ckeygen -*-
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.
-#
-# $Id: ckeygen.py,v 1.8 2003/05/10 14:03:40 spiv Exp $
+"""
+Implementation module for the `ckeygen` command.
+"""
-#""" Implementation module for the `ckeygen` command.
-#"""
-
-from twisted.conch.ssh import keys
-from twisted.python import log, usage, randbytes
-
-import sys, os, getpass, md5, socket
+import sys, os, getpass, socket
if getpass.getpass == getpass.unix_getpass:
try:
import termios # hack around broken termios
@@ -19,6 +15,10 @@
sys.modules['termios'] = None
reload(getpass)
+from twisted.conch.ssh import keys
+from twisted.python import filepath, log, usage, randbytes
+
+
class GeneralOptions(usage.Options):
synopsis = """Usage: ckeygen [options]
"""
@@ -88,6 +88,7 @@
key = DSA.generate(int(options['bits']), randbytes.secureRandom)
_saveKey(key, options)
+
def printFingerprint(options):
if not options['filename']:
filename = os.path.expanduser('~/.ssh/id_rsa')
@@ -95,11 +96,12 @@
if os.path.exists(options['filename']+'.pub'):
options['filename'] += '.pub'
try:
- string = keys.getPublicKeyString(options['filename'])
- obj = keys.getPublicKeyObject(string)
+ key = keys.Key.fromFile(options['filename'])
+ obj = key.keyObject
+ string = key.blob()
print '%s %s %s' % (
- obj.size()+1,
- ':'.join(['%02x' % ord(x) for x in md5.new(string).digest()]),
+ obj.size() + 1,
+ key.fingerprint(),
os.path.basename(options['filename']))
except:
sys.exit('bad key')
@@ -163,17 +165,21 @@
break
print 'Passphrases do not match. Try again.'
options['pass'] = p1
+
+ keyObj = keys.Key(key)
comment = '%s@%s' % (getpass.getuser(), socket.gethostname())
- open(options['filename'], 'w').write(
- keys.makePrivateKeyString(key, passphrase=options['pass']))
+
+ filepath.FilePath(options['filename']).setContent(
+ keyObj.toString('openssh', options['pass']))
os.chmod(options['filename'], 33152)
- open(options['filename']+'.pub', 'w').write(
- keys.makePublicKeyString(key, comment = comment))
- pubKey = keys.getPublicKeyString(data=keys.makePublicKeyString(key, comment=comment))
+
+ filepath.FilePath(options['filename'] + '.pub').setContent(
+ keyObj.public().toString('openssh', comment))
+
print 'Your identification has been saved in %s' % options['filename']
print 'Your public key has been saved in %s.pub' % options['filename']
print 'The key fingerprint is:'
- print ':'.join(['%02x' % ord(x) for x in md5.new(pubKey).digest()])
+ print keyObj.fingerprint()
if __name__ == '__main__':
run()
--- twisted/conch/ssh/keys.py
+++ twisted/conch/ssh/keys.py
@@ -10,7 +10,6 @@
# base library imports
import base64
-import sha, md5
import warnings
# external library imports
@@ -20,6 +19,7 @@
# twisted
from twisted.python import randbytes
+from twisted.python.hashlib import md5, sha1
# sibling imports
from twisted.conch.ssh import asn1, common, sexpy
@@ -205,8 +205,8 @@
len(ivdata), 2)])
if not passphrase:
raise EncryptedKeyError('encrypted key with no passphrase')
- ba = md5.new(passphrase + iv).digest()
- bb = md5.new(ba + passphrase + iv).digest()
+ ba = md5(passphrase + iv).digest()
+ bb = md5(ba + passphrase + iv).digest()
decKey = (ba + bb)[:24]
b64Data = base64.decodestring(''.join(lines[3:-1]))
keyData = DES3.new(decKey, DES3.MODE_CBC, iv).decrypt(b64Data)
@@ -443,7 +443,7 @@
@rtype: L{str}
"""
- return ':'.join([x.encode('hex') for x in md5.md5(self.blob()).digest()])
+ return ':'.join([x.encode('hex') for x in md5(self.blob()).digest()])
def type(self):
@@ -597,8 +597,8 @@
hexiv = ''.join(['%02X' % ord(x) for x in iv])
lines.append('Proc-Type: 4,ENCRYPTED')
lines.append('DEK-Info: DES-EDE3-CBC,%s\n' % hexiv)
- ba = md5.new(extra + iv).digest()
- bb = md5.new(ba + extra + iv).digest()
+ ba = md5(extra + iv).digest()
+ bb = md5(ba + extra + iv).digest()
encKey = (ba + bb)[:24]
asn1Data = asn1.pack([objData])
if extra:
@@ -681,7 +681,7 @@
signature = self.keyObject.sign(digest, '')[0]
ret = common.NS(Util.number.long_to_bytes(signature))
elif self.type() == 'DSA':
- digest = sha.new(data).digest()
+ digest = sha1(data).digest()
randomBytes = randbytes.secureRandom(19)
sig = self.keyObject.sign(digest, randomBytes)
# SSH insists that the DSS signature blob be two 160-bit integers
@@ -710,7 +710,7 @@
signature = common.getNS(signature)[0]
numbers = [Util.number.bytes_to_long(n) for n in signature[:20],
signature[20:]]
- digest = sha.new(data).digest()
+ digest = sha1(data).digest()
return self.keyObject.verify(digest, numbers)
def getPublicKeyString(filename=None, line=0, data=''):
@@ -863,7 +863,7 @@
@type data: C{str}
@type messageLength: C{str}
"""
- digest = sha.new(data).digest()
+ digest = sha1(data).digest()
return pkcs1Pad(ID_SHA1+digest, messageLength)
def lenSig(obj):
--- twisted/conch/ssh/transport.py
+++ twisted/conch/ssh/transport.py
@@ -13,8 +13,6 @@
# base library imports
import struct
-import md5
-import sha
import zlib
import array
@@ -26,6 +24,7 @@
from twisted.internet import protocol, defer
from twisted.conch import error
from twisted.python import log, randbytes
+from twisted.python.hashlib import md5, sha1
# sibling imports
from twisted.conch.ssh import keys
@@ -532,9 +531,9 @@
@type sharedSecret: C{str}
@type exchangeHash: C{str}
"""
- k1 = sha.new(sharedSecret + exchangeHash + c + self.sessionID)
+ k1 = sha1(sharedSecret + exchangeHash + c + self.sessionID)
k1 = k1.digest()
- k2 = sha.new(sharedSecret + exchangeHash + k1).digest()
+ k2 = sha1(sharedSecret + exchangeHash + k1).digest()
return k1 + k2
@@ -723,7 +722,7 @@
y = Util.number.getRandomNumber(512, randbytes.secureRandom)
serverDHpublicKey = _MPpow(DH_GENERATOR, y, DH_PRIME)
sharedSecret = _MPpow(clientDHpublicKey, y, DH_PRIME)
- h = sha.new()
+ h = sha1()
h.update(NS(self.otherVersionString))
h.update(NS(self.ourVersionString))
h.update(NS(self.otherKexInitPayload))
@@ -792,7 +791,7 @@
serverDHpublicKey = _MPpow(self.g, y, self.p)
sharedSecret = _MPpow(clientDHpublicKey, y, self.p)
- h = sha.new()
+ h = sha1()
h.update(NS(self.otherVersionString))
h.update(NS(self.ourVersionString))
h.update(NS(self.otherKexInitPayload))
@@ -933,7 +932,7 @@
f, packet = getMP(packet)
signature, packet = getNS(packet)
fingerprint = ':'.join([ch.encode('hex') for ch in
- md5.new(pubKey).digest()])
+ md5(pubKey).digest()])
d = self.verifyHostKey(pubKey, fingerprint)
d.addCallback(self._continueKEXDH_REPLY, pubKey, f, signature)
d.addErrback(
@@ -962,7 +961,7 @@
"""
serverKey = keys.Key.fromString(pubKey)
sharedSecret = _MPpow(f, self.x, DH_PRIME)
- h = sha.new()
+ h = sha1()
h.update(NS(self.ourVersionString))
h.update(NS(self.otherVersionString))
h.update(NS(self.ourKexInitPayload))
@@ -992,7 +991,7 @@
f, packet = getMP(packet)
signature, packet = getNS(packet)
fingerprint = ':'.join(map(lambda c: '%02x'%ord(c),
- md5.new(pubKey).digest()))
+ md5(pubKey).digest()))
d = self.verifyHostKey(pubKey, fingerprint)
d.addCallback(self._continueGEX_REPLY, pubKey, f, signature)
d.addErrback(
@@ -1015,7 +1014,7 @@
"""
serverKey = keys.Key.fromString(pubKey)
sharedSecret = _MPpow(f, self.x, self.p)
- h = sha.new()
+ h = sha1()
h.update(NS(self.ourVersionString))
h.update(NS(self.otherVersionString))
h.update(NS(self.ourKexInitPayload))
@@ -1169,9 +1168,9 @@
'none':(None, 0, 0),
}
macMap = {
- 'hmac-sha1': sha,
+ 'hmac-sha1': sha1,
'hmac-md5': md5,
- 'none':None
+ 'none': None
}
@@ -1243,10 +1242,7 @@
mod = self.macMap[mac]
if not mod:
return (None, '', '', 0)
- #if not hasattr(mod, 'digest_size'):
- # ds = len(mod.new().digest())
- #else:
- ds = mod.digest_size
+ ds = mod().digest_size
key = key[:ds] + '\x00' * (64 - ds)
i = XOR.new('\x36').encrypt(key)
o = XOR.new('\x5c').encrypt(key)
@@ -1287,8 +1283,8 @@
return ''
data = struct.pack('>L', seqid) + data
mod, i, o, ds = self.outMAC
- inner = mod.new(i + data)
- outer = mod.new(o + inner.digest())
+ inner = mod(i + data)
+ outer = mod(o + inner.digest())
return outer.digest()
@@ -1309,8 +1305,8 @@
return mac == ''
data = struct.pack('>L', seqid) + data
mod, i, o, ds = self.inMAC
- inner = mod.new(i + data)
- outer = mod.new(o + inner.digest())
+ inner = mod(i + data)
+ outer = mod(o + inner.digest())
return mac == outer.digest()
--- twisted/conch/test/test_ckeygen.py
+++ twisted/conch/test/test_ckeygen.py
@@ -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())
+
--- twisted/conch/test/test_keys.py
+++ twisted/conch/test/test_keys.py
@@ -12,10 +12,11 @@
else:
from twisted.conch.ssh import keys, common, sexpy, asn1
+import os, base64
from twisted.conch.test import keydata
from twisted.python import randbytes
+from twisted.python.hashlib import sha1
from twisted.trial import unittest
-import sha, os, base64
class SSHKeysHandlingTestCase(unittest.TestCase):
"""
@@ -330,7 +331,7 @@
messageSize = 6
self.assertEquals(keys.pkcs1Pad(data, messageSize),
'\x01\xff\x00ABC')
- hash = sha.new().digest()
+ hash = sha1().digest()
messageSize = 40
self.assertEquals(keys.pkcs1Digest('', messageSize),
'\x01\xff\xff\xff\x00' + keys.ID_SHA1 + hash)
@@ -362,7 +363,7 @@
"""
data = 'data'
key, sig = self._signDSA(data)
- sigData = sha.new(data).digest()
+ sigData = sha1(data).digest()
v = key.sign(sigData, '\x55' * 19)
self.assertEquals(sig, common.NS('ssh-dss') + common.NS(
Crypto.Util.number.long_to_bytes(v[0], 20) +
--- twisted/conch/test/test_transport.py
+++ twisted/conch/test/test_transport.py
@@ -5,8 +5,6 @@
Tests for ssh/transport.py and the classes therein.
"""
-import md5, sha
-
try:
import Crypto.Cipher.DES3
except ImportError:
@@ -27,6 +25,7 @@
from twisted.protocols import loopback
from twisted.python import randbytes
from twisted.python.reflect import qual
+from twisted.python.hashlib import md5, sha1
from twisted.conch.ssh import service
from twisted.test import proto_helpers
@@ -856,9 +855,8 @@
"""
self.proto.sessionID = 'EF'
- k1 = sha.new('AB' + 'CD'
- + 'K' + self.proto.sessionID).digest()
- k2 = sha.new('ABCD' + k1).digest()
+ k1 = sha1('AB' + 'CD' + 'K' + self.proto.sessionID).digest()
+ k2 = sha1('ABCD' + k1).digest()
self.assertEquals(self.proto._getKey('K', 'AB', 'CD'), k1 + k2)
@@ -1109,7 +1107,7 @@
f = common._MPpow(transport.DH_GENERATOR, y, transport.DH_PRIME)
sharedSecret = common._MPpow(e, y, transport.DH_PRIME)
- h = sha.new()
+ h = sha1()
h.update(common.NS(self.proto.ourVersionString) * 2)
h.update(common.NS(self.proto.ourKexInitPayload) * 2)
h.update(common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob()))
@@ -1190,7 +1188,7 @@
y = common.getMP('\x00\x00\x00\x80' + '\x99' * 128)[0]
f = common._MPpow(self.proto.g, y, self.proto.p)
sharedSecret = common._MPpow(e, y, self.proto.p)
- h = sha.new()
+ h = sha1()
h.update(common.NS(self.proto.ourVersionString) * 2)
h.update(common.NS(self.proto.ourKexInitPayload) * 2)
h.update(common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob()))
@@ -1221,7 +1219,7 @@
y = common.getMP('\x00\x00\x00\x80' + '\x99' * 128)[0]
f = common._MPpow(self.proto.g, y, self.proto.p)
sharedSecret = common._MPpow(e, y, self.proto.p)
- h = sha.new()
+ h = sha1()
h.update(common.NS(self.proto.ourVersionString) * 2)
h.update(common.NS(self.proto.ourKexInitPayload) * 2)
h.update(common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob()))
@@ -1360,7 +1358,7 @@
self.calledVerifyHostKey = True
self.assertEquals(pubKey, self.blob)
self.assertEquals(fingerprint.replace(':', ''),
- md5.new(pubKey).hexdigest())
+ md5(pubKey).hexdigest())
return defer.succeed(True)
@@ -1427,7 +1425,7 @@
sharedSecret = common._MPpow(transport.DH_GENERATOR,
self.proto.x, transport.DH_PRIME)
- h = sha.new()
+ h = sha1()
h.update(common.NS(self.proto.ourVersionString) * 2)
h.update(common.NS(self.proto.ourKexInitPayload) * 2)
h.update(common.NS(self.blob))
@@ -1476,7 +1474,7 @@
self.test_KEX_DH_GEX_GROUP()
sharedSecret = common._MPpow(3, self.proto.x, self.proto.p)
- h = sha.new()
+ h = sha1()
h.update(common.NS(self.proto.ourVersionString) * 2)
h.update(common.NS(self.proto.ourKexInitPayload) * 2)
h.update(common.NS(self.blob))
@@ -1654,7 +1652,7 @@
Crypto.Cipher.XOR.new('\x36').encrypt(key))
self.assertEquals(mod[2],
Crypto.Cipher.XOR.new('\x5c').encrypt(key))
- self.assertEquals(mod[3], len(mod[0].new().digest()))
+ self.assertEquals(mod[3], len(mod[0]().digest()))
def test_setKeysCiphers(self):
@@ -1693,7 +1691,7 @@
outMac.setKeys('', '', '', '', key, '')
inMac.setKeys('', '', '', '', '', key)
if mod:
- ds = mod.digest_size
+ ds = mod().digest_size
else:
ds = 0
self.assertEquals(inMac.verifyDigestSize, ds)
@@ -1703,7 +1701,7 @@
data = key
packet = '\x00' * 4 + key
if mod:
- mac = mod.new(o + mod.new(i + packet).digest()).digest()
+ mac = mod(o + mod(i + packet).digest()).digest()
else:
mac = ''
self.assertEquals(outMac.makeMAC(seqid, data), mac)
--- twisted/cred/util.py
+++ twisted/cred/util.py
@@ -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.hashlib import md5
from twisted.cred.error import Unauthorized
+
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
--- twisted/internet/_sslverify.py
+++ twisted/internet/_sslverify.py
@@ -1,11 +1,13 @@
# -*- test-case-name: twisted.test.test_sslverify -*-
-# Copyright 2005 Divmod, Inc. See LICENSE file for details
+# Copyright 2005 Divmod, Inc.
# Copyright (c) 2005-2008 Twisted Matrix Laboratories.
+# See LICENSE for details.
-import itertools, md5
+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
@@ -452,7 +454,7 @@
MD5 hex digest of signature on an empty certificate request with this
key.
"""
- return md5.md5(self._emptyReq).hexdigest()
+ return md5(self._emptyReq).hexdigest()
def inspect(self):
@@ -736,7 +738,7 @@
ctx.set_options(self._OP_ALL)
if self.enableSessions:
- sessionName = md5.md5("%s-%d" % (reflect.qual(self.__class__), _sessionCounter())).hexdigest()
+ sessionName = md5("%s-%d" % (reflect.qual(self.__class__), _sessionCounter())).hexdigest()
ctx.set_session_id(sessionName)
if not self.enableSessionTickets:
--- twisted/mail/maildir.py
+++ twisted/mail/maildir.py
@@ -12,7 +12,6 @@
import stat
import socket
import time
-import md5
import cStringIO
from zope.interface import implements
@@ -27,6 +26,7 @@
from twisted.protocols import basic
from twisted.persisted import dirdbm
from twisted.python import log, failure
+from twisted.python.hashlib import md5
from twisted.mail import mail
from twisted.mail import alias
from twisted.internet import interfaces, defer, reactor
@@ -298,7 +298,7 @@
"""
# Returning the actual filename is a mistake. Hash it.
base = os.path.basename(self.list[i])
- return md5.md5(base).hexdigest()
+ return md5(base).hexdigest()
def deleteMessage(self, i):
"""Delete a message
@@ -355,7 +355,7 @@
return StringIO.StringIO(self.msgs[i])
def getUidl(self, i):
- return md5.new(self.msgs[i]).hexdigest()
+ return md5(self.msgs[i]).hexdigest()
def deleteMessage(self, i):
pass
--- twisted/mail/pop3.py
+++ twisted/mail/pop3.py
@@ -1,6 +1,6 @@
# -*- test-case-name: twisted.mail.test.test_pop3 -*-
#
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.
@@ -14,7 +14,6 @@
import string
import base64
import binascii
-import md5
import warnings
from zope.interface import implements, Interface
@@ -26,6 +25,7 @@
from twisted.internet import defer
from twisted.internet import interfaces
from twisted.python import log
+from twisted.python.hashlib import md5
from twisted import cred
import twisted.cred.error
@@ -44,7 +44,7 @@
def checkPassword(self, password):
seed = self.magic + password
- myDigest = md5.new(seed).hexdigest()
+ myDigest = md5(seed).hexdigest()
return myDigest == self.digest
@@ -1031,7 +1031,7 @@
self._dispatch(self.command+"_continue", None, line)
def apopAuthenticate(self, user, password, magic):
- digest = md5.new(magic + password).hexdigest()
+ digest = md5(magic + password).hexdigest()
self.apop(user, digest)
def apop(self, user, digest):
--- twisted/mail/pop3client.py
+++ twisted/mail/pop3client.py
@@ -1,5 +1,6 @@
# -*- test-case-name: twisted.mail.test.test_pop3client -*-
# Copyright (c) 2001-2004 Divmod Inc.
+# Copyright (c) 2008 Twisted Matrix Laboratories.
# See LICENSE for details.
"""
@@ -10,9 +11,10 @@
@author: Jp Calderone
"""
-import re, md5
+import re
from twisted.python import log
+from twisted.python.hashlib import md5
from twisted.internet import defer
from twisted.protocols import basic
from twisted.protocols import policies
@@ -485,7 +487,7 @@
def _apop(self, username, password, challenge):
# Internal helper. Computes and sends an APOP response. Returns
# a Deferred that fires when the server responds to the response.
- digest = md5.new(challenge + password).hexdigest()
+ digest = md5(challenge + password).hexdigest()
return self.apop(username, digest)
def apop(self, username, digest):
--- twisted/mail/test/test_mail.py
+++ twisted/mail/test/test_mail.py
@@ -7,7 +7,6 @@
import os
import errno
-import md5
import shutil
import pickle
import StringIO
@@ -32,6 +31,7 @@
from twisted.internet import address
from twisted.python import failure
from twisted.python.filepath import FilePath
+from twisted.python.hashlib import md5
from twisted import mail
import twisted.mail.mail
@@ -587,7 +587,7 @@
shutil.rmtree(self.tmpdir)
def testAuthenticateAPOP(self):
- resp = md5.new(self.P.magic + 'password').hexdigest()
+ resp = md5(self.P.magic + 'password').hexdigest()
return self.P.authenticateUserAPOP('user', resp
).addCallback(self._cbAuthenticateAPOP
)
@@ -599,13 +599,13 @@
result[2]()
def testAuthenticateIncorrectUserAPOP(self):
- resp = md5.new(self.P.magic + 'password').hexdigest()
+ resp = md5(self.P.magic + 'password').hexdigest()
return self.assertFailure(
self.P.authenticateUserAPOP('resu', resp),
cred.error.UnauthorizedLogin)
def testAuthenticateIncorrectResponseAPOP(self):
- resp = md5.new('wrong digest').hexdigest()
+ resp = md5('wrong digest').hexdigest()
return self.assertFailure(
self.P.authenticateUserAPOP('user', resp),
cred.error.UnauthorizedLogin)
--- twisted/news/database.py
+++ twisted/news/database.py
@@ -1,5 +1,5 @@
# -*- test-case-name: twisted.news.test.test_news -*-
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.
@@ -13,18 +13,19 @@
"""
-from __future__ import nested_scopes
+import getpass, pickle, time, socket
+import os
+import StringIO
+
+from zope.interface import implements, Interface
from twisted.news.nntp import NNTPError
from twisted.mail import smtp
from twisted.internet import defer
from twisted.enterprise import adbapi
from twisted.persisted import dirdbm
+from twisted.python.hashlib import md5
-import getpass, pickle, time, socket, md5
-import os
-import StringIO
-from zope.interface import implements, Interface
ERR_NOGROUP, ERR_NOARTICLE = range(2, 4) # XXX - put NNTP values here (I guess?)
@@ -53,15 +54,15 @@
if not self.getHeader('Message-ID'):
s = str(time.time()) + self.body
- id = hexdigest(md5.md5(s)) + '@' + socket.gethostname()
+ id = hexdigest(md5(s)) + '@' + socket.gethostname()
self.putHeader('Message-ID', '<%s>' % id)
if not self.getHeader('Bytes'):
self.putHeader('Bytes', str(len(self.body)))
-
+
if not self.getHeader('Lines'):
self.putHeader('Lines', str(self.body.count('\n')))
-
+
if not self.getHeader('Date'):
self.putHeader('Date', time.ctime(time.time()))
@@ -83,7 +84,7 @@
for i in self.headers.values():
headers.append('%s: %s' % i)
return '\r\n'.join(headers) + '\r\n'
-
+
def overview(self):
xover = []
for i in OVERVIEW_FMT:
@@ -94,12 +95,12 @@
class NewsServerError(Exception):
pass
-
+
class INewsStorage(Interface):
"""
An interface for storing and requesting news articles
"""
-
+
def listRequest():
"""
Returns a deferred whose callback will be passed a list of 4-tuples
@@ -112,16 +113,16 @@
Returns a deferred whose callback will be passed the list of
recommended subscription groups for new server users
"""
-
-
+
+
def postRequest(message):
"""
Returns a deferred whose callback will be invoked if 'message'
is successfully posted to one or more specified groups and
whose errback will be invoked otherwise.
"""
-
-
+
+
def overviewRequest():
"""
Returns a deferred whose callback will be passed the a list of
@@ -146,21 +147,21 @@
ends at the last article.
"""
-
+
def listGroupRequest(group):
"""
Returns a deferred whose callback will be passed a two-tuple of
(group name, [article indices])
"""
-
-
+
+
def groupRequest(group):
"""
Returns a deferred whose callback will be passed a five-tuple of
(group name, article count, highest index, lowest index, group flags)
"""
-
+
def articleExistsRequest(id):
"""
Returns a deferred whose callback will be passed with a true value
@@ -170,7 +171,7 @@
def articleRequest(group, index, id = None):
- """
+ """
Returns a deferred whose callback will be passed a file-like object
containing the full article text (headers and body) for the article
of the specified index in the specified group, and whose errback
@@ -180,7 +181,7 @@
group.
"""
-
+
def headRequest(group, index):
"""
Returns a deferred whose callback will be passed the header for
@@ -189,7 +190,7 @@
exist.
"""
-
+
def bodyRequest(group, index):
"""
Returns a deferred whose callback will be passed the body for
@@ -231,7 +232,7 @@
class PickleStorage:
"""A trivial NewsStorage implementation using pickles
-
+
Contains numerous flaws and is generally unsuitable for any
real applications. Consider yourself warned!
"""
@@ -388,8 +389,8 @@
return defer.fail(ERR_NOARTICLE)
else:
return defer.fail(ERR_NOGROUP)
-
-
+
+
def headRequest(self, group, index):
if self.db.has_key(group):
if self.db[group].has_key(index):
@@ -441,7 +442,7 @@
minArticle = 1
maxArticle = 0
articles = None
-
+
def __init__(self, name, flags = 'y'):
self.name = name
self.flags = flags
@@ -452,9 +453,9 @@
"""
A NewStorage implementation using Twisted's dirdbm persistence module.
"""
-
- implements(INewsStorage)
-
+
+ implements(INewsStorage)
+
def __init__(self, mailhost, path):
self.path = path
self.mailhost = mailhost
@@ -502,8 +503,8 @@
def subscriptionRequest(self):
return defer.succeed(self.dbm['subscriptions'])
-
-
+
+
def getModerator(self, groups):
# first see if any groups are moderated. if so, nothing gets posted,
# but the whole messages gets forwarded to the moderator address
@@ -532,17 +533,17 @@
def postRequest(self, message):
cleave = message.find('\r\n\r\n')
headers, article = message[:cleave], message[cleave + 4:]
-
+
article = Article(headers, article)
groups = article.getHeader('Newsgroups').split()
xref = []
-
+
# Check for moderated status
moderator = self.getModerator(groups)
if moderator and not article.getHeader('Approved'):
return self.notifyModerator(moderator, article)
-
-
+
+
for group in groups:
try:
g = self.dbm['groups'][group]
@@ -570,7 +571,7 @@
def xoverRequest(self, group, low, high):
if not self.dbm['groups'].has_key(group):
return defer.succeed([])
-
+
if low is None:
low = 0
if high is None:
@@ -585,7 +586,7 @@
def xhdrRequest(self, group, low, high, header):
if group not in self.dbm['groups']:
return defer.succeed([])
-
+
if low is None:
low = 0
if high is None:
@@ -618,8 +619,8 @@
def articleExistsRequest(self, id):
return defer.succeed(id in self.dbm['Message-IDs'])
-
-
+
+
def articleRequest(self, group, index, id = None):
if id is not None:
try:
@@ -629,7 +630,7 @@
else:
group, index = xref[0]
index = int(index)
-
+
try:
a = self.dbm['groups'][group].articles[index]
except KeyError:
@@ -640,8 +641,8 @@
a.getHeader('Message-ID'),
StringIO.StringIO(a.textHeaders() + '\r\n' + a.body)
))
-
-
+
+
def headRequest(self, group, index, id = None):
if id is not None:
try:
@@ -651,7 +652,7 @@
else:
group, index = xref[0]
index = int(index)
-
+
try:
a = self.dbm['groups'][group].articles[index]
except KeyError:
@@ -669,7 +670,7 @@
else:
group, index = xref[0]
index = int(index)
-
+
try:
a = self.dbm['groups'][group].articles[index]
except KeyError:
@@ -690,7 +691,7 @@
CREATE TABLE groups (
group_id SERIAL,
name VARCHAR(80) NOT NULL,
-
+
flags INTEGER DEFAULT 0 NOT NULL
);
@@ -700,7 +701,7 @@
CREATE TABLE articles (
article_id SERIAL,
message_id TEXT,
-
+
header TEXT,
body TEXT
);
@@ -719,16 +720,16 @@
CREATE TABLE subscriptions (
group_id INTEGER
);
-
+
CREATE TABLE overview (
header TEXT
);
"""
-
+
def __init__(self, info):
self.info = info
self.dbpool = adbapi.ConnectionPool(**self.info)
-
+
def __setstate__(self, state):
self.__dict__ = state
@@ -778,14 +779,14 @@
SELECT name, group_id FROM groups
WHERE name IN (%s)
""" % (', '.join([("'%s'" % (adbapi.safe(group),)) for group in groups]),)
-
+
transaction.execute(sql)
result = transaction.fetchall()
-
+
# No relevant groups, bye bye!
if not len(result):
raise NNTPError('None of groups in Newsgroup header carried')
-
+
# Got some groups, now find the indices this article will have in each
sql = """
SELECT groups.group_id, COALESCE(MAX(postings.article_index), 0) + 1
@@ -800,20 +801,20 @@
if not len(indices):
raise NNTPError('Internal server error - no indices found')
-
+
# Associate indices with group names
gidToName = dict([(b, a) for (a, b) in result])
gidToIndex = dict(indices)
-
+
nameIndex = []
for i in gidToName:
nameIndex.append((gidToName[i], gidToIndex[i]))
-
+
# Build xrefs
xrefs = socket.gethostname().split()[0]
xrefs = xrefs + ' ' + ' '.join([('%s:%d' % (group, id)) for (group, id) in nameIndex])
article.putHeader('Xref', xrefs)
-
+
# Hey! The article is ready to be posted! God damn f'in finally.
sql = """
INSERT INTO articles (message_id, header, body)
@@ -823,9 +824,9 @@
adbapi.safe(article.textHeaders()),
adbapi.safe(article.body)
)
-
+
transaction.execute(sql)
-
+
# Now update the posting to reflect the groups to which this belongs
for gid in gidToName:
sql = """
@@ -833,7 +834,7 @@
VALUES (%d, (SELECT last_value FROM articles_article_id_seq), %d)
""" % (gid, gidToIndex[gid])
transaction.execute(sql)
-
+
return len(nameIndex)
@@ -888,13 +889,13 @@
WHERE postings.group_id = groups.group_id
AND groups.name = '%s'
""" % (adbapi.safe(group),)
-
+
return self.dbpool.runQuery(sql).addCallback(
lambda results, group = group: (group, [res[0] for res in results])
)
- def groupRequest(self, group):
+ def groupRequest(self, group):
sql = """
SELECT groups.name,
COUNT(postings.article_index),
@@ -906,7 +907,7 @@
WHERE groups.name = '%s'
GROUP BY groups.name, groups.flags
""" % (adbapi.safe(group),)
-
+
return self.dbpool.runQuery(sql).addCallback(
lambda results: tuple(results[0])
)
@@ -917,7 +918,7 @@
SELECT COUNT(message_id) FROM articles
WHERE message_id = '%s'
""" % (adbapi.safe(id),)
-
+
return self.dbpool.runQuery(sql).addCallback(
lambda result: bool(result[0][0])
)
@@ -933,7 +934,7 @@
AND groups.group_id = postings.group_id
""" % (adbapi.safe(id), adbapi.safe(group))
else:
- sql = """
+ sql = """
SELECT postings.article_index, articles.message_id, articles.header, articles.body
FROM groups,articles LEFT OUTER JOIN postings
ON postings.article_id = articles.article_id
@@ -960,7 +961,7 @@
AND postings.group_id = groups.group_id
AND groups.name = '%s'
""" % (index, adbapi.safe(group))
-
+
return self.dbpool.runQuery(sql).addCallback(lambda result: result[0])
@@ -973,7 +974,7 @@
AND postings.group_id = groups.group_id
AND groups.name = '%s'
""" % (index, adbapi.safe(group))
-
+
return self.dbpool.runQuery(sql).addCallback(
lambda result: result[0]
).addCallback(
--- twisted/persisted/sob.py
+++ twisted/persisted/sob.py
@@ -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):
--- twisted/protocols/sip.py
+++ twisted/protocols/sip.py
@@ -1,6 +1,6 @@
# -*- test-case-name: twisted.test.test_sip -*-
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.
@@ -14,12 +14,12 @@
import socket
import random
import time
-import md5
import sys
from zope.interface import implements, Interface
# twisted imports
from twisted.python import log, util
+from twisted.python.hashlib import md5
from twisted.internet import protocol, defer, reactor
from twisted import cred
@@ -132,7 +132,7 @@
pszNonce,
pszCNonce,
):
- m = md5.md5()
+ m = md5()
m.update(pszUserName)
m.update(":")
m.update(pszRealm)
@@ -140,7 +140,7 @@
m.update(pszPassword)
HA1 = m.digest()
if pszAlg == "md5-sess":
- m = md5.md5()
+ m = md5()
m.update(HA1)
m.update(":")
m.update(pszNonce)
@@ -159,7 +159,7 @@
pszDigestUri,
pszHEntity,
):
- m = md5.md5()
+ m = md5()
m.update(pszMethod)
m.update(":")
m.update(pszDigestUri)
@@ -168,7 +168,7 @@
m.update(pszHEntity)
HA2 = m.digest().encode('hex')
- m = md5.md5()
+ m = md5()
m.update(HA1)
m.update(":")
m.update(pszNonce)
--- twisted/python/filepath.py
+++ twisted/python/filepath.py
@@ -9,7 +9,6 @@
import os
import errno
import random
-import sha
import base64
from os.path import isabs, exists, normpath, abspath, splitext
@@ -25,6 +24,7 @@
# modified for inclusion in the standard library. --glyph
from twisted.python.runtime import platform
+from twisted.python.hashlib import sha1
from twisted.python.win32 import ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND
from twisted.python.win32 import ERROR_INVALID_NAME, ERROR_DIRECTORY
@@ -120,7 +120,7 @@
"""
Create a pseudorandom, 16-character string for use in secure filenames.
"""
- return armor(sha.new(randomBytes(64)).digest())[:16]
+ return armor(sha1(randomBytes(64)).digest())[:16]
--- twisted/python/hashlib.py
+++ twisted/python/hashlib.py
@@ -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"]
--- twisted/python/otp.py
+++ twisted/python/otp.py
@@ -1,7 +1,9 @@
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# -*- test-case-name: twisted.python.test.test_otp -*-
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.
-""" A One-Time Password System based on RFC 2289
+"""
+A One-Time Password System based on RFC 2289
The class Authenticator contains the hashing-logic, and the parser for the
readable output. It also contains challenge which returns a string describing
@@ -17,11 +19,21 @@
Uses the MD5- and SHA-algorithms for hashing
Todo: RFC2444, SASL (perhaps), parsing hex-responses
+
+This module is deprecated. Consider using U{another Python OTP
+library<http://labix.org/python-otp>} instead.
"""
+import warnings
import string
import random
+warnings.warn(
+ "twisted.python.otp is deprecated since Twisted 8.3.",
+ category=DeprecationWarning,
+ stacklevel=2)
+
+
def stringToLong(s):
""" Convert digest to long """
result = 0L
@@ -47,33 +59,37 @@
result = chr(l % 256) + result
l = l / 256L
return result
-
-import md5, sha
-hashid = {md5: 'md5', sha: 'sha1'}
+
+from twisted.python.hashlib import md5, sha1
+hashid = {md5: 'md5', sha1: 'sha1'}
INITIALSEQUENCE = 1000
MINIMUMSEQUENCE = 50
class Unauthorized(Exception):
"""the Unauthorized exception
-
+
This exception is raised when an action is not allowed, or a user is not
authenticated properly.
"""
class OTPAuthenticator:
- """A One Time Password System
-
+ """
+ A One Time Password System
+
Based on RFC 2289, which is based on a the S/KEY Authentication-scheme.
It uses the MD5- and SHA-algorithms for hashing
-
- The variable OTP is at all times a 64bit string"""
+ The variable OTP is at all times a 64bit string.
+
+ @ivar hash: An object which can be used to compute hashes. This is either
+ L{md5} or L{sha1}.
+ """
def __init__(self, hash = md5):
"Set the hash to either md5 or sha1"
self.hash = hash
- pass
-
+
+
def generateSeed(self):
"Return a 10 char random seed, with 6 lowercase chars and 4 digits"
seed = ''
@@ -86,9 +102,9 @@
def foldDigest(self, otp):
if self.hash == md5:
return self.foldDigest128(otp)
- if self.hash == sha:
+ if self.hash == sha1:
return self.foldDigest160(otp)
-
+
def foldDigest128(self, otp128):
"Fold a 128 bit digest to 64 bit"
regs = stringToDWords(otp128)
@@ -120,9 +136,9 @@
def hashUpdate(self, digest):
"Run through the hash and fold to 64 bit"
- h = self.hash.new(digest)
+ h = self.hash(digest)
return self.foldDigest(h.digest())
-
+
def generateOTP(self, seed, passwd, sequence):
"""Return a 64 bit OTP based on inputs
Run through makeReadable to get a 6 word pass-phrase"""
@@ -138,7 +154,7 @@
for i in xrange(0, 64, 2):
parity = parity + otp & 0x3
otp = otp >> 2
- return parity
+ return parity
def makeReadable(self, otp):
"Returns a 6 word pass-phrase from a 64bit OTP"
@@ -151,7 +167,7 @@
return string.join(list)
def challenge(self, seed, sequence):
- """Return a challenge in the format otp-<hash> <sequence> <seed>"""
+ """Return a challenge in the format otp-<hash> <sequence> <seed>"""
return "otp-%s %i %s" % (hashid[self.hash], sequence, seed)
def parsePhrase(self, phrase):
@@ -178,9 +194,9 @@
On the next authentication, the stored password is hashed and checked
up against the one given by the user. If they match, the sequencecounter
is decreased and the circle is closed.
-
+
This object should be glued to each user
-
+
Note:
It does NOT reset the sequence when the combinations left approach zero,
This has to be done manuelly by instancing a new object
@@ -478,4 +494,3 @@
"WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE", "YANG", "YANK",
"YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR", "YELL", "YOGA",
"YOKE"]
-
--- twisted/python/test/test_hashlib.py
+++ twisted/python/test/test_hashlib.py
@@ -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)
--- twisted/python/test/test_zipstream.py
+++ twisted/python/test/test_zipstream.py
@@ -6,10 +6,10 @@
"""
import sys
import random
-import md5
import zipfile
from twisted.python import zipstream, filepath
+from twisted.python.hashlib import md5
from twisted.trial import unittest
class FileEntryMixin:
@@ -347,7 +347,7 @@
unzipIterChunky should unzip the given number of bytes per iteration.
"""
junk = ' '.join([str(random.random()) for n in xrange(1000)])
- junkmd5 = md5.new(junk).hexdigest()
+ junkmd5 = md5(junk).hexdigest()
tempdir = filepath.FilePath(self.mktemp())
tempdir.makedirs()
@@ -364,7 +364,7 @@
for r in uziter:
pass
self.assertEqual(r, 0)
- newmd5 = md5.new(
+ newmd5 = md5(
tempdir.child("zipstreamjunk").open().read()).hexdigest()
self.assertEqual(newmd5, junkmd5)
--- twisted/spread/pb.py
+++ twisted/spread/pb.py
@@ -27,7 +27,6 @@
@author: Glyph Lefkowitz
"""
-import md5
import random
import new
import types
@@ -38,6 +37,7 @@
from twisted.python import log, failure, reflect
from twisted.python.versions import Version
from twisted.python.deprecate import deprecated
+from twisted.python.hashlib import md5
from twisted.internet import defer, protocol
from twisted.cred.portal import Portal
from twisted.cred.credentials import IAnonymous, ICredentials
@@ -997,10 +997,10 @@
This is useful for challenge/response authentication.
"""
- m = md5.new()
+ m = md5()
m.update(password)
hashedPassword = m.digest()
- m = md5.new()
+ m = md5()
m.update(hashedPassword)
m.update(challenge)
doubleHashedPassword = m.digest()
@@ -1011,7 +1011,7 @@
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
@@ -1340,12 +1340,12 @@
# IUsernameHashedPassword:
def checkPassword(self, password):
- return self.checkMD5Password(md5.md5(password).digest())
+ return self.checkMD5Password(md5(password).digest())
# IUsernameMD5Password
def checkMD5Password(self, md5Password):
- md = md5.new()
+ md = md5()
md.update(md5Password)
md.update(self.challenge)
correct = md.digest()
--- twisted/test/test_newcred.py
+++ twisted/test/test_newcred.py
@@ -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
--- twisted/trial/test/test_loader.py
+++ twisted/trial/test/test_loader.py
@@ -5,12 +5,12 @@
Tests for loading tests by name.
"""
-import md5
import os
import shutil
import sys
from twisted.python import util
+from twisted.python.hashlib import md5
from twisted.trial.test import packages
from twisted.trial import runner, reporter, unittest
from twisted.trial.itrial import ITestCase
@@ -484,7 +484,7 @@
# if isinstance(s, type) or isinstance(s, types.ClassType):
# return s.__module__+'.'+s.__name__
n = runner.name(s)
- d = md5.new(n).hexdigest()
+ d = md5(n).hexdigest()
return d
self.loadSortedPackages(sillySorter)
--- twisted/web/_auth/digest.py
+++ twisted/web/_auth/digest.py
@@ -9,10 +9,10 @@
"""
import time
-import md5, sha
from zope.interface import implements
+from twisted.python.hashlib import md5, sha1
from twisted.python.randbytes import secureRandom
from twisted.cred import credentials, error
from twisted.web.iweb import ICredentialFactory, IUsernameDigestHash
@@ -21,7 +21,7 @@
# The digest math
algorithms = {
- 'md5': md5.new,
+ 'md5': md5,
# md5-sess is more complicated than just another algorithm. It requires
# H(A1) state to be remembered from the first WWW-Authenticate challenge
@@ -30,9 +30,9 @@
# recalculate H(A1) each time an Authorization header is received. Read
# RFC 2617, section 3.2.2.2 and do not try to make DigestCredentialFactory
# support this unless you completely understand it. -exarkun
- 'md5-sess': md5.new,
+ 'md5-sess': md5,
- 'sha': sha.new,
+ 'sha': sha1,
}
# DigestCalcHA1
@@ -257,7 +257,7 @@
if clientip is None:
clientip = ''
key = "%s,%s,%s" % (nonce, clientip, now)
- digest = md5.new(key + self.privateKey).hexdigest()
+ digest = md5(key + self.privateKey).hexdigest()
ekey = key.encode('base64')
return "%s-%s" % (digest, ekey.strip('\n'))
@@ -315,7 +315,7 @@
'Invalid response, incompatible opaque/nonce too old')
# Verify the digest
- digest = md5.new(key + self.privateKey).hexdigest()
+ digest = md5(key + self.privateKey).hexdigest()
if digest != opaqueParts[0]:
raise error.LoginFailed('Invalid response, invalid opaque value')
--- twisted/web/monitor.py
+++ twisted/web/monitor.py
@@ -1,85 +0,0 @@
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
-# See LICENSE for details.
-
-#
-from twisted.web import client
-from twisted.internet import reactor
-import md5
-from zope.interface import implements
-
-class IChangeNotified:
- pass
-
-class BaseChangeNotified:
-
- implements(IChangeNotified)
-
- def reportChange(self, old, new):
- pass
-
- def reportNoChange(self):
- pass
-
-class ChangeChecker:
-
- working = 0
- call = None
-
- def __init__(self, notified, url, delay=60):
- self.notified = notified
- self.url = url
- self.md5 = None
- self.delay = delay
-
- def start(self):
- self.working = 1
- self._getPage()
-
- def stop(self):
- if self.call:
- self.call.cancel()
- self.call = None
- self.working = 0
-
- def _getPage(self):
- d = client.getPage(self.url)
- d.addErrback(self.noPage)
- d.addCallback(self.page)
- self.call = None
-
- def noPage(self, e):
- self.gotMD5(None)
-
- def page(self, p):
- if p is None:
- return self.gotMD5(None)
- m = md5.new()
- m.update(p)
- self.gotMD5(m.digest())
-
- def gotMD5(self, md5):
- if not self.working:
- return
- if md5 != self.md5:
- self.notified.reportChange(self.md5, md5)
- self.md5 = md5
- else:
- self.notified.reportNoChange()
- if not self.call:
- self.call = reactor.callLater(self.delay, self._getPage)
-
-
-class ProxyChangeChecker(ChangeChecker):
-
- def __init__(self, proxyHost, proxyPort, notified, url, delay=60):
- self.proxyHost = proxyHost
- self.proxyPort = proxyPort
- ChangeChecker.__init__(self, notified, url, delay)
-
- def _getPage(self):
- factory = client.HTTPClientFactory(self.proxyHost, self.url)
- factory.headers = {'pragma': 'no-cache'}
- reactor.connectTCP(self.proxyHost, self.proxyPort, factory)
- d = factory.deferred
- d.addErrback(self.noPage)
- d.addCallback(self.page)
--- twisted/web/server.py
+++ twisted/web/server.py
@@ -1,6 +1,6 @@
# -*- test-case-name: twisted.web.test.test_web -*-
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.
@@ -507,9 +507,10 @@
"""
(internal) Generate an opaque, unique ID for a user's session.
"""
- import md5, random
+ from twisted.python.hashlib import md5
+ import random
self.counter = self.counter + 1
- return md5.new("%s_%s" % (str(random.random()) , str(self.counter))).hexdigest()
+ return md5("%s_%s" % (str(random.random()) , str(self.counter))).hexdigest()
def makeSession(self):
"""
--- twisted/web/test/test_httpauth.py
+++ twisted/web/test/test_httpauth.py
@@ -5,11 +5,11 @@
Tests for L{twisted.web._auth}.
"""
-import md5, sha
from zope.interface import implements
from zope.interface.verify import verifyObject
+from twisted.python.hashlib import md5, sha1
from twisted.trial import unittest
from twisted.cred import error, portal
from twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse
@@ -181,7 +181,7 @@
self.algorithm, self.realm)
- def test_MD5HashA1(self, _algorithm='md5', _hash=md5.md5):
+ def test_MD5HashA1(self, _algorithm='md5', _hash=md5):
"""
L{calcHA1} accepts the C{'md5'} algorithm and returns an MD5 hash of
its parameters, excluding the nonce and cnonce.
@@ -203,9 +203,9 @@
hashA1 = calcHA1('md5-sess', self.username, self.realm, self.password,
nonce, self.cnonce)
a1 = '%s:%s:%s' % (self.username, self.realm, self.password)
- ha1 = md5.md5(a1).digest()
+ ha1 = md5(a1).digest()
a1 = '%s:%s:%s' % (ha1, nonce, self.cnonce)
- expected = md5.md5(a1).hexdigest()
+ expected = md5(a1).hexdigest()
self.assertEqual(hashA1, expected)
@@ -214,10 +214,10 @@
L{calcHA1} accepts the C{'sha'} algorithm and returns a SHA hash of its
parameters, excluding the nonce and cnonce.
"""
- self.test_MD5HashA1('sha', sha.sha)
+ self.test_MD5HashA1('sha', sha1)
- def test_MD5HashA2Auth(self, _algorithm='md5', _hash=md5.md5):
+ def test_MD5HashA2Auth(self, _algorithm='md5', _hash=md5):
"""
L{calcHA2} accepts the C{'md5'} algorithm and returns an MD5 hash of
its arguments, excluding the entity hash for QOP other than
@@ -230,7 +230,7 @@
self.assertEqual(hashA2, expected)
- def test_MD5HashA2AuthInt(self, _algorithm='md5', _hash=md5.md5):
+ def test_MD5HashA2AuthInt(self, _algorithm='md5', _hash=md5):
"""
L{calcHA2} accepts the C{'md5'} algorithm and returns an MD5 hash of
its arguments, including the entity hash for QOP of C{'auth-int'}.
@@ -265,7 +265,7 @@
its arguments, excluding the entity hash for QOP other than
C{'auth-int'}.
"""
- self.test_MD5HashA2Auth('sha', sha.sha)
+ self.test_MD5HashA2Auth('sha', sha1)
def test_SHAHashA2AuthInt(self):
@@ -273,10 +273,10 @@
L{calcHA2} accepts the C{'sha'} algorithm and returns a SHA hash of
its arguments, including the entity hash for QOP of C{'auth-int'}.
"""
- self.test_MD5HashA2AuthInt('sha', sha.sha)
+ self.test_MD5HashA2AuthInt('sha', sha1)
- def test_MD5HashResponse(self, _algorithm='md5', _hash=md5.md5):
+ def test_MD5HashResponse(self, _algorithm='md5', _hash=md5):
"""
L{calcResponse} accepts the C{'md5'} algorithm and returns an MD5 hash
of its parameters, excluding the nonce count, client nonce, and QoP
@@ -308,10 +308,10 @@
of its parameters, excluding the nonce count, client nonce, and QoP
value if the nonce count and client nonce are C{None}
"""
- self.test_MD5HashResponse('sha', sha.sha)
+ self.test_MD5HashResponse('sha', sha1)
- def test_MD5HashResponseExtra(self, _algorithm='md5', _hash=md5.md5):
+ def test_MD5HashResponseExtra(self, _algorithm='md5', _hash=md5):
"""
L{calcResponse} accepts the C{'md5'} algorithm and returns an MD5 hash
of its parameters, including the nonce count, client nonce, and QoP
@@ -348,7 +348,7 @@
of its parameters, including the nonce count, client nonce, and QoP
value if they are specified.
"""
- self.test_MD5HashResponseExtra('sha', sha.sha)
+ self.test_MD5HashResponseExtra('sha', sha1)
def makeRequest(self, method='GET', clientAddress=None):
@@ -639,7 +639,7 @@
self.assertTrue(verifyObject(IUsernameDigestHash, creds))
cleartext = '%s:%s:%s' % (self.username, self.realm, self.password)
- hash = md5.md5(cleartext)
+ hash = md5(cleartext)
self.assertTrue(creds.checkHash(hash.hexdigest()))
hash.update('wrong')
self.assertFalse(creds.checkHash(hash.hexdigest()))
@@ -761,7 +761,7 @@
key = '%s,%s,%s' % (challenge['nonce'],
self.clientAddress.host,
'-137876876')
- digest = md5.md5(key + credentialFactory.privateKey).hexdigest()
+ digest = md5(key + credentialFactory.privateKey).hexdigest()
ekey = b64encode(key)
oldNonceOpaque = '%s-%s' % (digest, ekey.strip('\n'))
@@ -786,7 +786,7 @@
self.clientAddress.host,
'0')
- digest = md5.md5(key + 'this is not the right pkey').hexdigest()
+ digest = md5(key + 'this is not the right pkey').hexdigest()
badChecksum = '%s-%s' % (digest, b64encode(key))
self.assertRaises(
--- twisted/web/woven/guard.py
+++ twisted/web/woven/guard.py
@@ -1,6 +1,6 @@
# -*- test-case-name: twisted.web.test.test_woven -*-
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.
#
@@ -16,12 +16,12 @@
import random
import time
-import md5
import urllib
# Twisted Imports
from twisted.python import log, components
+from twisted.python.hashlib import md5
from twisted.web.resource import Resource, IResource
from twisted.web.util import redirectTo, Redirect, DeferredResource
from twisted.web.static import addSlash
@@ -29,7 +29,7 @@
from twisted.cred.error import LoginFailed, UnauthorizedLogin
def _sessionCookie():
- return md5.new("%s_%s" % (str(random.random()) , str(time.time()))).hexdigest()
+ return md5("%s_%s" % (str(random.random()) , str(time.time()))).hexdigest()
class GuardSession(components.Componentized):
"""A user's session with a system.
--- twisted/words/protocols/jabber/sasl_mechanisms.py
+++ twisted/words/protocols/jabber/sasl_mechanisms.py
@@ -1,16 +1,18 @@
# -*- test-case-name: twisted.words.test.test_jabbersaslmechanisms -*-
#
-# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Protocol agnostic implementations of SASL authentication mechanisms.
"""
-import md5, binascii, random, time, os
+import binascii, random, time, os
from zope.interface import Interface, Attribute, implements
+from twisted.python.hashlib import md5
+
class ISASLMechanism(Interface):
name = Attribute("""Common name for the SASL Mechanism.""")
@@ -178,7 +180,7 @@
"""
def H(s):
- return md5.new(s).digest()
+ return md5(s).digest()
def HEX(n):
return binascii.b2a_hex(n)
@@ -221,4 +223,4 @@
def _gen_nonce(self):
- return md5.new("%s:%s:%s" % (str(random.random()) , str(time.gmtime()),str(os.getpid()))).hexdigest()
+ return md5("%s:%s:%s" % (str(random.random()) , str(time.gmtime()),str(os.getpid()))).hexdigest()
--- twisted/words/protocols/jabber/xmlstream.py
+++ twisted/words/protocols/jabber/xmlstream.py
@@ -42,8 +42,8 @@
"""
Create a SHA1-digest string of a session identifier and password.
"""
- import sha
- return sha.new("%s%s" % (sid, password)).hexdigest()
+ from twisted.python.hashlib import sha1
+ return sha1("%s%s" % (sid, password)).hexdigest()
--- twisted/words/protocols/msn.py
+++ twisted/words/protocols/msn.py
@@ -1,9 +1,7 @@
# -*- test-case-name: twisted.words.test -*-
-# Copyright (c) 2001-2005 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.
-#
-
"""
MSNP8 Protocol (client only) - semi-experimental
@@ -18,7 +16,7 @@
You will want to subclass this and handle the gotNotificationReferral
method appropriately.
-
+
I{Notification Server}
The NotificationClient class handles connections to the
@@ -73,11 +71,12 @@
@author: Sam Jordan
"""
-import types, operator, os, md5
+import types, operator, os
from random import randint
from urllib import quote, unquote
from twisted.python import failure, log
+from twisted.python.hashlib import md5
from twisted.internet import reactor
from twisted.internet.defer import Deferred
from twisted.internet.protocol import ClientFactory
@@ -185,7 +184,7 @@
class PassportNexus(HTTPClient):
-
+
"""
Used to obtain the URL of a valid passport
login HTTPS server.
@@ -330,7 +329,7 @@
If set to MESSAGE_ACK_NONE the server will do nothing.
This is relevant for the return value of
SwitchboardClient.sendMessage (which will return
- a Deferred if ack is set to either MESSAGE_ACK or MESSAGE_NACK
+ a Deferred if ack is set to either MESSAGE_ACK or MESSAGE_NACK
and will fire when the respective ACK or NACK is received).
If set to MESSAGE_ACK_NONE sendMessage will return None.
"""
@@ -379,7 +378,7 @@
self.message = message
class MSNContact:
-
+
"""
This class represents a contact (user).
@@ -401,7 +400,7 @@
@ivar hasPager: Whether or not this user has a mobile pager
(true=yes, false=no)
"""
-
+
def __init__(self, userHandle="", screenName="", lists=0, groups=[], status=None):
self.userHandle = userHandle
self.screenName = screenName
@@ -856,7 +855,7 @@
def handle_CHL(self, params):
checkParamLen(len(params), 2, 'CHL')
self.sendLine("QRY %s msmsgs@msnmsgr.com 32" % self._nextTransactionID())
- self.transport.write(md5.md5(params[1] + MSN_CHALLENGE_STR).hexdigest())
+ self.transport.write(md5(params[1] + MSN_CHALLENGE_STR).hexdigest())
def handle_QRY(self, params):
pass
@@ -1253,7 +1252,7 @@
a tuple with the new status code as the
only element.
"""
-
+
id, d = self._createIDMapping()
self.sendLine("CHG %s %s" % (id, status))
def _cb(r):
@@ -1304,7 +1303,7 @@
the state as 'bl' which the official client
interprets as -> allow messages from all
users except those on the block list.
-
+
@return: A Deferred, the callback of which will be fired when
the server replies with the new privacy setting.
The callback argument will be a tuple, the 2 elements
@@ -1362,7 +1361,7 @@
# if lists are synchronized and updated correctly, which they
# should be. If someone has a specific justified need for this
# then please contact me and i'll re-enable/fix support for it.
-
+
#def requestListGroups(self):
# """
# Request (forward) list groups.
@@ -1373,7 +1372,7 @@
# a dictionary mapping group IDs to group names and the
# current list version.
# """
- #
+ #
# # this doesn't need to be used if syncing of the lists takes place (which it SHOULD!)
# # i.e. please don't use it!
# warnings.warn("Please do not use this method - use the list syncing process instead")
@@ -1473,7 +1472,7 @@
the new list version (int), the group id (int) and
the new group name (str).
"""
-
+
id, d = self._createIDMapping()
self.sendLine("REG %s %s %s 0" % (id, groupID, quote(newName)))
def _cb(r):
@@ -1509,7 +1508,7 @@
version, and the group id (if relevant, otherwise it
will be None)
"""
-
+
id, d = self._createIDMapping()
listType = listIDToCode[listType].upper()
if listType == "FL":
@@ -1554,7 +1553,7 @@
version, and the group id (if relevant, otherwise it will
be None)
"""
-
+
id, d = self._createIDMapping()
listType = listIDToCode[listType].upper()
if listType == "FL":
@@ -1624,7 +1623,7 @@
After running the method the server is expected
to close the connection.
"""
-
+
self.sendLine("OUT")
class NotificationFactory(ClientFactory):
@@ -2117,7 +2116,7 @@
self.state = 'CONNECTING'
self.segmentLength = 0
self.buffer = ''
-
+
if isinstance(file, types.StringType):
path = os.path.join(directory, file)
if os.path.exists(path) and not self.overwrite:
@@ -2237,7 +2236,7 @@
@ivar auth: the auth cookie (number) to use when sending the
transfer invitation
"""
-
+
def __init__(self, file):
"""
@param file: A string or file object represnting the file to send.
--- twisted/words/protocols/oscar.py
+++ twisted/words/protocols/oscar.py
@@ -1,5 +1,5 @@
# -*- test-case-name: twisted.words.test -*-
-# Copyright (c) 2001-2005 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.
@@ -9,20 +9,17 @@
Maintainer: Paul Swartz
"""
-from __future__ import nested_scopes
-
-from twisted.internet import reactor, defer, protocol
-from twisted.python import log
-
import struct
-import md5
import string
import socket
import random
-import time
import types
import re
+from twisted.internet import reactor, defer, protocol
+from twisted.python import log
+from twisted.python.hashlib import md5
+
def logPacketData(data):
lines = len(data)/16
if lines*16 != len(data): lines=lines+1
@@ -62,9 +59,9 @@
return dict,data
def encryptPasswordMD5(password,key):
- m=md5.new()
+ m=md5()
m.update(key)
- m.update(md5.new(password).digest())
+ m.update(md5(password).digest())
m.update("AOL Instant Messenger (SM)")
return m.digest()
--- twisted/words/test/test_jabberclient.py
+++ twisted/words/test/test_jabberclient.py
@@ -1,11 +1,11 @@
-# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for L{twisted.words.protocols.jabber.client}
"""
-import sha
+from twisted.python.hashlib import sha1
from twisted.trial import unittest
from twisted.words.protocols.jabber import client, error, jid, xmlstream
from twisted.words.protocols.jabber.sasl import SASLInitiatingInitializer
@@ -117,7 +117,7 @@
self.assertEquals(('jabber:iq:auth', 'query'),
(iq.children[0].uri, iq.children[0].name))
self.assertEquals('user', unicode(iq.query.username))
- self.assertEquals(sha.new('12345secret').hexdigest(),
+ self.assertEquals(sha1('12345secret').hexdigest(),
unicode(iq.query.digest))
self.assertEquals('resource', unicode(iq.query.resource))
--- twisted/words/test/test_jabbercomponent.py
+++ twisted/words/test/test_jabbercomponent.py
@@ -5,9 +5,8 @@
Tests for L{twisted.words.protocols.jabber.component}
"""
-import sha
-
from twisted.python import failure
+from twisted.python.hashlib import sha1
from twisted.trial import unittest
from twisted.words.protocols.jabber import component, xmlstream
from twisted.words.protocols.jabber.jid import JID
@@ -50,7 +49,7 @@
handshake = self.output[-1]
self.assertEquals('handshake', handshake.name)
self.assertEquals('test:component', handshake.uri)
- self.assertEquals(sha.new("%s%s" % ('12345', 'secret')).hexdigest(),
+ self.assertEquals(sha1("%s%s" % ('12345', 'secret')).hexdigest(),
unicode(handshake))
# successful authentication
@@ -80,7 +79,7 @@
xs.dataReceived("<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='cjid' id='12345'>")
# Calculate what we expect the handshake value to be
- hv = sha.new("%s%s" % ("12345", "secret")).hexdigest()
+ hv = sha1("%s%s" % ("12345", "secret")).hexdigest()
self.assertEquals(outlist[1], "<handshake>%s</handshake>" % (hv))
--- twisted/words/test/test_msn.py
+++ twisted/words/test/test_msn.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2001-2005 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.
"""
@@ -6,7 +6,7 @@
"""
# System imports
-import StringIO, sys
+import StringIO
# Twisted imports
@@ -24,6 +24,7 @@
from twisted.words.protocols import msn
+from twisted.python.hashlib import md5
from twisted.protocols import loopback
from twisted.internet.defer import Deferred
from twisted.trial import unittest
@@ -255,10 +256,35 @@
self._versionTest("VER 1 MSNP8\r\n")
+ def test_challenge(self):
+ """
+ L{NotificationClient} responds to a I{CHL} message by sending a I{QRY}
+ back which included a hash based on the parameters of the I{CHL}.
+ """
+ transport = StringIOWithoutClosing()
+ self.client.makeConnection(transport)
+ transport.seek(0)
+ transport.truncate()
+
+ challenge = "15570131571988941333"
+ self.client.dataReceived('CHL 0 ' + challenge + '\r\n')
+ # md5 of the challenge and a magic string defined by the protocol
+ response = "8f2f5a91b72102cd28355e9fc9000d6e"
+ # Sanity check - the response is what the comment above says it is.
+ self.assertEqual(
+ response, md5(challenge + "Q1P7W2E4J9R8U3S5").hexdigest())
+ self.assertEqual(
+ transport.getvalue(),
+ # 2 is the next transaction identifier. 32 is the length of the
+ # response.
+ "QRY 2 msmsgs@msnmsgr.com 32\r\n" + response)
+
+
def testLogin(self):
self.client.lineReceived('USR 1 OK foo@bar.com Test%20Screen%20Name 1 0')
self.failUnless((self.client.state == 'LOGIN'), msg='Failed to detect successful login')
+
def testProfile(self):
m = 'MSG Hotmail Hotmail 353\r\nMIME-Version: 1.0\r\nContent-Type: text/x-msmsgsprofile; charset=UTF-8\r\n'
m += 'LoginTime: 1016941010\r\nEmailEnabled: 1\r\nMemberIdHigh: 40000\r\nMemberIdLow: -600000000\r\nlang_preference: 1033\r\n'
--- twisted/words/test/test_oscar.py
+++ twisted/words/test/test_oscar.py
@@ -0,0 +1,24 @@
+# Copyright (c) 2008 Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+Tests for L{twisted.words.protocols.oscar}.
+"""
+
+from twisted.trial.unittest import TestCase
+
+from twisted.words.protocols.oscar import encryptPasswordMD5
+
+
+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')