diff -Nru twisted-conch-10.2.0/bin/cftp twisted-conch-12.1.0/bin/cftp --- twisted-conch-10.2.0/bin/cftp 2009-04-08 21:56:55.000000000 +0000 +++ twisted-conch-12.1.0/bin/cftp 2011-06-30 12:57:11.000000000 +0000 @@ -1,20 +1,15 @@ #!/usr/bin/env python - -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. import sys, os -path = os.path.abspath(sys.argv[0]) -while os.path.dirname(path) != path: - if os.path.basename(path).startswith('Twisted'): - sys.path.insert(0, path) - break - path = os.path.dirname(path) -### end of preamble +extra = os.path.dirname(os.path.dirname(sys.argv[0])) +sys.path.insert(0, extra) +try: + import _preamble +except ImportError: + sys.exc_clear() +sys.path.remove(extra) from twisted.conch.scripts.cftp import run run() diff -Nru twisted-conch-10.2.0/bin/ckeygen twisted-conch-12.1.0/bin/ckeygen --- twisted-conch-10.2.0/bin/ckeygen 2009-04-08 21:56:55.000000000 +0000 +++ twisted-conch-12.1.0/bin/ckeygen 2011-06-30 12:57:11.000000000 +0000 @@ -1,20 +1,15 @@ #!/usr/bin/env python - -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. import sys, os -path = os.path.abspath(sys.argv[0]) -while os.path.dirname(path) != path: - if os.path.basename(path).startswith('Twisted'): - sys.path.insert(0, path) - break - path = os.path.dirname(path) -### end of preamble +extra = os.path.dirname(os.path.dirname(sys.argv[0])) +sys.path.insert(0, extra) +try: + import _preamble +except ImportError: + sys.exc_clear() +sys.path.remove(extra) from twisted.conch.scripts.ckeygen import run run() diff -Nru twisted-conch-10.2.0/bin/conch twisted-conch-12.1.0/bin/conch --- twisted-conch-10.2.0/bin/conch 2009-04-08 21:56:55.000000000 +0000 +++ twisted-conch-12.1.0/bin/conch 2011-06-30 12:57:11.000000000 +0000 @@ -1,20 +1,15 @@ #!/usr/bin/env python - -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. import sys, os -path = os.path.abspath(sys.argv[0]) -while os.path.dirname(path) != path: - if os.path.basename(path).startswith('Twisted'): - sys.path.insert(0, path) - break - path = os.path.dirname(path) -### end of preamble +extra = os.path.dirname(os.path.dirname(sys.argv[0])) +sys.path.insert(0, extra) +try: + import _preamble +except ImportError: + sys.exc_clear() +sys.path.remove(extra) from twisted.conch.scripts.conch import run run() diff -Nru twisted-conch-10.2.0/bin/tkconch twisted-conch-12.1.0/bin/tkconch --- twisted-conch-10.2.0/bin/tkconch 2009-04-08 21:56:55.000000000 +0000 +++ twisted-conch-12.1.0/bin/tkconch 2011-06-30 12:57:11.000000000 +0000 @@ -1,20 +1,15 @@ #!/usr/bin/env python - -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - -### Twisted Preamble -# This makes sure that users don't have to set up their environment -# specially in order to run these programs from bin/. import sys, os -path = os.path.abspath(sys.argv[0]) -while os.path.dirname(path) != path: - if os.path.basename(path).startswith('Twisted'): - sys.path.insert(0, path) - break - path = os.path.dirname(path) -### end of preamble +extra = os.path.dirname(os.path.dirname(sys.argv[0])) +sys.path.insert(0, extra) +try: + import _preamble +except ImportError: + sys.exc_clear() +sys.path.remove(extra) from twisted.conch.scripts.tkconch import run run() diff -Nru twisted-conch-10.2.0/debian/changelog twisted-conch-12.1.0/debian/changelog --- twisted-conch-10.2.0/debian/changelog 2011-02-24 10:42:07.000000000 +0000 +++ twisted-conch-12.1.0/debian/changelog 2012-06-29 02:04:09.000000000 +0000 @@ -1,3 +1,29 @@ +twisted-conch (1:12.1.0-1~ppa1~natty1) natty; urgency=low + + * New upstream version. + * Rebuild package for use in PPA. + + -- Jessica McKellar Thu, 28 Jun 2012 22:03:49 -0400 + +twisted-conch (1:12.0.0-1~ppa1~natty1) natty; urgency=low + + * New upstream version. + * Rebuild package for use in PPA. + + -- Jessica McKellar Wed, 15 Feb 2012 11:33:40 -0500 + +twisted-conch (1:11.1.0-1) unstable; urgency=low + + * New upstream version. + + -- Matthias Klose Wed, 21 Dec 2011 12:44:30 +0100 + +twisted-conch (1:11.0.0-1) unstable; urgency=low + + * New upstream version. + + -- Matthias Klose Mon, 18 Apr 2011 22:31:15 +0200 + twisted-conch (1:10.2.0-1) unstable; urgency=low * New upstream release. diff -Nru twisted-conch-10.2.0/debian/compat twisted-conch-12.1.0/debian/compat --- twisted-conch-10.2.0/debian/compat 2010-07-21 07:55:03.000000000 +0000 +++ twisted-conch-12.1.0/debian/compat 2012-06-19 02:11:56.000000000 +0000 @@ -1 +1 @@ -5 +7 diff -Nru twisted-conch-10.2.0/debian/control twisted-conch-12.1.0/debian/control --- twisted-conch-10.2.0/debian/control 2011-02-24 10:41:18.000000000 +0000 +++ twisted-conch-12.1.0/debian/control 2012-06-19 02:14:43.000000000 +0000 @@ -3,19 +3,18 @@ Priority: optional Maintainer: Matthias Klose Uploaders: Free Ekanayaka -Build-Depends: debhelper (>= 5.0.37.2), patch -Build-Depends-Indep: python-all (>= 2.6.5-9~), python-twisted-core (>= 10.2) +Build-Depends: debhelper (>=7.0.50~), patch, python-all (>= 2.6.6-3~) +Build-Depends-Indep: python-twisted-core (>= 12.1) Build-Conflicts: python-setuptools XS-Python-Version: all -Standards-Version: 3.9.1 +Standards-Version: 3.9.2 Package: python-twisted-conch Architecture: all -Depends: ${python:Depends}, python-crypto (>= 2.0.1+dfsg1-1.1), python-pyasn1, python-twisted-core (>= 10.2), ${misc:Depends} +Depends: ${python:Depends}, python-crypto (>= 2.0.1+dfsg1-1.1), python-pyasn1, python-twisted-core (>= 12.1), ${misc:Depends} Provides: conch, ${python:Provides} -Conflicts: python2.3-twisted (<< 2.2), python2.3-twisted-conch, python2.4-twisted-conch -Replaces: python2.3-twisted (<< 2.2), python2.3-twisted-conch, python2.4-twisted-conch -XB-Python-Version: ${python:Versions} -Description: The Twisted SSH Implementation +Conflicts: python2.3-twisted, python2.3-twisted-conch, python2.4-twisted-conch +Replaces: python2.3-twisted, python2.3-twisted-conch, python2.4-twisted-conch +Description: Twisted SSH Implementation A client/server implementation of the SSH protocol, using the twisted framework. diff -Nru twisted-conch-10.2.0/debian/patches/debian-changes-1:12.1.0-1~ppa1~natty1 twisted-conch-12.1.0/debian/patches/debian-changes-1:12.1.0-1~ppa1~natty1 --- twisted-conch-10.2.0/debian/patches/debian-changes-1:12.1.0-1~ppa1~natty1 1970-01-01 00:00:00.000000000 +0000 +++ twisted-conch-12.1.0/debian/patches/debian-changes-1:12.1.0-1~ppa1~natty1 2012-06-29 02:04:23.000000000 +0000 @@ -0,0 +1,37 @@ +Description: Upstream changes introduced in version 1:12.1.0-1~ppa1~natty1 + This patch has been created by dpkg-source during the package build. + Here's the last changelog entry, hopefully it gives details on why + those changes were made: + . + twisted-conch (1:12.1.0-1~ppa1~natty1) natty; urgency=low + . + * New upstream version. + * Rebuild package for use in PPA. + . + The person named in the Author field signed this changelog entry. +Author: Jessica McKellar + +--- +The information above should follow the Patch Tagging Guidelines, please +checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here +are templates for supplementary fields that you might want to add: + +Origin: , +Bug: +Bug-Debian: http://bugs.debian.org/ +Bug-Ubuntu: https://launchpad.net/bugs/ +Forwarded: +Reviewed-By: +Last-Update: + +--- twisted-conch-12.1.0.orig/doc/man/cftp.1 ++++ twisted-conch-12.1.0/doc/man/cftp.1 +@@ -12,7 +12,7 @@ + .Op Fl s Ar subsystem + .Os + .Sh DESCRIPTION +-.Nm cftp ++.Nm + is a client for logging into a remote machine and executing commands to send and receive file information. It can wrap a number of file transfer subsystems + .Pp + The options are as follows: diff -Nru twisted-conch-10.2.0/debian/patches/series twisted-conch-12.1.0/debian/patches/series --- twisted-conch-10.2.0/debian/patches/series 2011-02-24 10:44:14.000000000 +0000 +++ twisted-conch-12.1.0/debian/patches/series 2012-06-29 02:04:23.000000000 +0000 @@ -1 +1,2 @@ cftp-man.diff +debian-changes-1:12.1.0-1~ppa1~natty1 diff -Nru twisted-conch-10.2.0/debian/rules twisted-conch-12.1.0/debian/rules --- twisted-conch-10.2.0/debian/rules 2010-07-21 08:00:29.000000000 +0000 +++ twisted-conch-12.1.0/debian/rules 2012-06-19 02:11:56.000000000 +0000 @@ -8,6 +8,8 @@ VER := $(shell /usr/bin/python -c 'import sys; print sys.version[:3]') build: build-stamp +build-arch: build-stamp +build-indep: build-stamp build-stamp: $(PYVERS:%=build-python%) touch $@ build-python%: @@ -26,7 +28,7 @@ install-prereq: build-stamp dh_testdir dh_testroot - dh_clean -k + dh_prep install-python%: install-prereq : # python-twisted-conch diff -Nru twisted-conch-10.2.0/debian/watch twisted-conch-12.1.0/debian/watch --- twisted-conch-10.2.0/debian/watch 2011-02-24 10:46:25.000000000 +0000 +++ twisted-conch-12.1.0/debian/watch 2012-06-19 02:11:56.000000000 +0000 @@ -1,2 +1,2 @@ version=3 -http://tmrc.mit.edu/mirror/twisted/Conch/(\d+\.\d)/ TwistedConch-([\d\.]*)\.tar\.bz2 +http://tmrc.mit.edu/mirror/twisted/Conch/(\d\.\d)/ TwistedConch-([\d\.]*)\.tar\.bz2 diff -Nru twisted-conch-10.2.0/doc/benchmarks/buffering_mixin.py twisted-conch-12.1.0/doc/benchmarks/buffering_mixin.py --- twisted-conch-10.2.0/doc/benchmarks/buffering_mixin.py 2006-10-23 02:57:58.000000000 +0000 +++ twisted-conch-12.1.0/doc/benchmarks/buffering_mixin.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2006 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/doc/examples/demo_draw.tac twisted-conch-12.1.0/doc/examples/demo_draw.tac --- twisted-conch-10.2.0/doc/examples/demo_draw.tac 2010-03-21 23:11:14.000000000 +0000 +++ twisted-conch-12.1.0/doc/examples/demo_draw.tac 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # You can run this .tac file directly with: diff -Nru twisted-conch-10.2.0/doc/examples/demo_insults.tac twisted-conch-12.1.0/doc/examples/demo_insults.tac --- twisted-conch-10.2.0/doc/examples/demo_insults.tac 2008-08-17 18:51:31.000000000 +0000 +++ twisted-conch-12.1.0/doc/examples/demo_insults.tac 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # You can run this .tac file directly with: diff -Nru twisted-conch-10.2.0/doc/examples/demo_manhole.tac twisted-conch-12.1.0/doc/examples/demo_manhole.tac --- twisted-conch-10.2.0/doc/examples/demo_manhole.tac 2008-08-17 18:51:31.000000000 +0000 +++ twisted-conch-12.1.0/doc/examples/demo_manhole.tac 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # You can run this .tac file directly with: diff -Nru twisted-conch-10.2.0/doc/examples/demo_recvline.tac twisted-conch-12.1.0/doc/examples/demo_recvline.tac --- twisted-conch-10.2.0/doc/examples/demo_recvline.tac 2008-08-17 18:51:31.000000000 +0000 +++ twisted-conch-12.1.0/doc/examples/demo_recvline.tac 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # You can run this .tac file directly with: diff -Nru twisted-conch-10.2.0/doc/examples/demo_scroll.tac twisted-conch-12.1.0/doc/examples/demo_scroll.tac --- twisted-conch-10.2.0/doc/examples/demo_scroll.tac 2008-08-17 18:51:31.000000000 +0000 +++ twisted-conch-12.1.0/doc/examples/demo_scroll.tac 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # You can run this .tac file directly with: diff -Nru twisted-conch-10.2.0/doc/examples/demo.tac twisted-conch-12.1.0/doc/examples/demo.tac --- twisted-conch-10.2.0/doc/examples/demo.tac 2008-08-17 18:51:31.000000000 +0000 +++ twisted-conch-12.1.0/doc/examples/demo.tac 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # You can run this .tac file directly with: diff -Nru twisted-conch-10.2.0/doc/examples/index.html twisted-conch-12.1.0/doc/examples/index.html --- twisted-conch-10.2.0/doc/examples/index.html 2010-11-30 03:13:25.000000000 +0000 +++ twisted-conch-12.1.0/doc/examples/index.html 2012-06-04 08:46:24.000000000 +0000 @@ -1,11 +1,11 @@ -Twisted Documentation: Twisted.Conch code examples +Twisted Documentation: Twisted Conch code examples -

Twisted.Conch code examples

+

Twisted Conch code examples

@@ -35,6 +35,6 @@

Index

- Version: 10.2.0 + Version: 12.1.0 \ No newline at end of file diff -Nru twisted-conch-10.2.0/doc/examples/sshsimpleclient.py twisted-conch-12.1.0/doc/examples/sshsimpleclient.py --- twisted-conch-10.2.0/doc/examples/sshsimpleclient.py 2010-05-30 18:13:04.000000000 +0000 +++ twisted-conch-12.1.0/doc/examples/sshsimpleclient.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (c) 2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.conch.ssh import transport, userauth, connection, common, keys, channel diff -Nru twisted-conch-10.2.0/doc/examples/sshsimpleserver.py twisted-conch-12.1.0/doc/examples/sshsimpleserver.py --- twisted-conch-10.2.0/doc/examples/sshsimpleserver.py 2010-05-30 18:13:04.000000000 +0000 +++ twisted-conch-12.1.0/doc/examples/sshsimpleserver.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (c) 2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.cred import portal, checkers diff -Nru twisted-conch-10.2.0/doc/examples/telnet_echo.tac twisted-conch-12.1.0/doc/examples/telnet_echo.tac --- twisted-conch-10.2.0/doc/examples/telnet_echo.tac 2009-11-08 15:02:32.000000000 +0000 +++ twisted-conch-12.1.0/doc/examples/telnet_echo.tac 2012-04-08 13:10:57.000000000 +0000 @@ -1,6 +1,16 @@ -# Copyright (c) 2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. +""" +Simple echo server that echoes back client input. + +You can run this .tac file directly with: + twistd -ny telnet_echo.tac + +This demo sets up a listening port on 6023 which accepts telnet connections. +No login for the telnet server is required. +""" + from twisted.conch.telnet import TelnetTransport, TelnetProtocol from twisted.internet.protocol import ServerFactory from twisted.application.internet import TCPServer diff -Nru twisted-conch-10.2.0/doc/examples/window.tac twisted-conch-12.1.0/doc/examples/window.tac --- twisted-conch-10.2.0/doc/examples/window.tac 2008-08-17 18:51:31.000000000 +0000 +++ twisted-conch-12.1.0/doc/examples/window.tac 2012-04-08 13:10:57.000000000 +0000 @@ -1,8 +1,20 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. -# You can run this .tac file directly with: -# twistd -ny window.tac +""" +Widgets demo. + +You can run this .tac file directly with: + twistd -ny window.tac + +Demonstrates various widgets or buttons, such as scrollable regions, +drawable canvas, etc. + +This demo sets up two listening ports: one on 6022 which accepts ssh +connections; one on 6023 which accepts telnet connections. No login for the +telnet server is required; for the ssh server, "username" is the username and +"password" is the password. +""" from __future__ import division diff -Nru twisted-conch-10.2.0/doc/howto/conch_client.html twisted-conch-12.1.0/doc/howto/conch_client.html --- twisted-conch-10.2.0/doc/howto/conch_client.html 2010-11-30 03:13:25.000000000 +0000 +++ twisted-conch-12.1.0/doc/howto/conch_client.html 2012-06-04 08:46:24.000000000 +0000 @@ -1,11 +1,11 @@ -Twisted Documentation: Writing a client with Twisted.Conch +Twisted Documentation: Writing a client with Twisted Conch -

Writing a client with Twisted.Conch

+

Writing a client with Twisted Conch

@@ -15,12 +15,12 @@

In the original days of computing, rsh/rlogin were used to connect to remote computers and execute commands. These commands had the problem that the passwords and commands were sent in the clear. To solve this -problem, the SSH protocol was created. Twisted.Conch implements the +problem, the SSH protocol was created. Twisted Conch implements the second version of this protocol.

Writing a client

-

Writing a client with Conch involves sub-classing 4 classes: twisted.conch.ssh.transport.SSHClientTransport, twisted.conch.ssh.userauth.SSHUserAuthClient, twisted.conch.ssh.connection.SSHConnection, and twisted.conch.ssh.channel.SSHChannel. We'll start out +

Writing a client with Conch involves sub-classing 4 classes: twisted.conch.ssh.transport.SSHClientTransport, twisted.conch.ssh.userauth.SSHUserAuthClient, twisted.conch.ssh.connection.SSHConnection, and twisted.conch.ssh.channel.SSHChannel. We'll start out with SSHClientTransport because it's the base of the client.

@@ -63,7 +63,7 @@ is called with two strings: the public key sent by the server and its fingerprint. You should verify the host key the server sends, either by checking against a hard-coded value as in the example, or by asking -the user. verifyHostKey returns a twisted.internet.defer.Deferred which gets a callback +the user. verifyHostKey returns a twisted.internet.defer.Deferred which gets a callback if the host key is valid, or an errback if it is not. Note that in the above, replace 'user' with the username you're attempting to ssh with, for instance a call to os.getlogin() for the @@ -249,14 +249,14 @@ send the request for this channel. The 2nd argument of 'exec' tells the server that we want to execute a command. The third argument is the data that accompanies the request. -common.NS encodes +common.NS encodes the data as a length-prefixed string, which is how the server expects the data. We also say that we want a reply saying that the process has a been started. sendRequest() then returns a Deferred which we add a callback for.

Once the callback fires, we send the data. SSHChannel supports the -twisted.internet.interfaces.ITransport +twisted.internet.interfaces.ITransport interface, so it can be given to Protocols to run them over the secure connection. In our case, we just write the data directly. sendEOF() does not follow the interface, @@ -294,7 +294,7 @@

We call connectTCP() to connect to localhost, port 22 (the standard port for ssh), and pass it an instance -of twisted.internet.protocol.ClientFactory. +of twisted.internet.protocol.ClientFactory. This instance has the attribute protocol set to our earlier ClientTransport class. Note that the protocol attribute is set to the class ClientTransport, not an instance of @@ -316,6 +316,6 @@

Index

- Version: 10.2.0 + Version: 12.1.0 \ No newline at end of file diff -Nru twisted-conch-10.2.0/doc/howto/index.html twisted-conch-12.1.0/doc/howto/index.html --- twisted-conch-10.2.0/doc/howto/index.html 2010-11-30 03:13:25.000000000 +0000 +++ twisted-conch-12.1.0/doc/howto/index.html 2012-06-04 08:46:24.000000000 +0000 @@ -23,6 +23,6 @@

Index

- Version: 10.2.0 + Version: 12.1.0 \ No newline at end of file diff -Nru twisted-conch-10.2.0/doc/index.html twisted-conch-12.1.0/doc/index.html --- twisted-conch-10.2.0/doc/index.html 2010-11-30 03:13:25.000000000 +0000 +++ twisted-conch-12.1.0/doc/index.html 2012-06-04 08:46:24.000000000 +0000 @@ -20,6 +20,6 @@

Index

- Version: 10.2.0 + Version: 12.1.0 \ No newline at end of file diff -Nru twisted-conch-10.2.0/doc/man/cftp-man.html twisted-conch-12.1.0/doc/man/cftp-man.html --- twisted-conch-10.2.0/doc/man/cftp-man.html 2010-11-30 03:13:25.000000000 +0000 +++ twisted-conch-12.1.0/doc/man/cftp-man.html 2012-06-04 08:46:24.000000000 +0000 @@ -82,6 +82,6 @@

Index

- Version: 10.2.0 + Version: 12.1.0 \ No newline at end of file diff -Nru twisted-conch-10.2.0/doc/man/ckeygen.1 twisted-conch-12.1.0/doc/man/ckeygen.1 --- twisted-conch-10.2.0/doc/man/ckeygen.1 2008-08-10 18:06:13.000000000 +0000 +++ twisted-conch-12.1.0/doc/man/ckeygen.1 2011-01-16 22:07:11.000000000 +0000 @@ -1,11 +1,10 @@ .TH CKEYGEN "1" "October 2002" "" "" .SH NAME -ckeygen \- connect to SSH servers +ckeygen \- manipulate public/private keys .SH SYNOPSIS .B ckeygen [-b \fIbits\fR] [-f \fIfilename\fR] [-t \fItype\fR] .B [-C \fIcomment\fR] [-N \fInew passphrase\fR] [-P \fIold passphrase\fR] .B [-l] [-p] [-q] [-y] -.B ckeygen --help .SH DESCRIPTION .PP The \fB\--help\fR prints out a usage message to standard output. @@ -50,7 +49,7 @@ .SH "REPORTING BUGS" To report a bug, visit \fIhttp://twistedmatrix.com/bugs/\fR .SH COPYRIGHT -Copyright \(co 2002-2008 Twisted Matrix Laboratories. +Copyright \(co 2002-2011 Twisted Matrix Laboratories. .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff -Nru twisted-conch-10.2.0/doc/man/ckeygen-man.html twisted-conch-12.1.0/doc/man/ckeygen-man.html --- twisted-conch-10.2.0/doc/man/ckeygen-man.html 2010-11-30 03:13:25.000000000 +0000 +++ twisted-conch-12.1.0/doc/man/ckeygen-man.html 2012-06-04 08:46:24.000000000 +0000 @@ -13,12 +13,12 @@

NAME

-

ckeygen - connect to SSH servers +

ckeygen - manipulate public/private keys

SYNOPSIS

-

ckeygen [-b bits] [-f filename] [-t type][-C comment] [-N new passphrase] [-P old passphrase][-l] [-p] [-q] [-y]ckeygen --help

+

ckeygen [-b bits] [-f filename] [-t type][-C comment] [-N new passphrase] [-P old passphrase][-l] [-p] [-q] [-y]

DESCRIPTION

@@ -89,7 +89,7 @@

COPYRIGHT

-

Copyright © 2002-2008 Twisted Matrix Laboratories. +

Copyright © 2002-2011 Twisted Matrix Laboratories. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

@@ -102,6 +102,6 @@

Index

- Version: 10.2.0 + Version: 12.1.0 \ No newline at end of file diff -Nru twisted-conch-10.2.0/doc/man/conch-man.html twisted-conch-12.1.0/doc/man/conch-man.html --- twisted-conch-10.2.0/doc/man/conch-man.html 2010-11-30 03:13:25.000000000 +0000 +++ twisted-conch-12.1.0/doc/man/conch-man.html 2012-06-04 08:46:24.000000000 +0000 @@ -143,6 +143,6 @@

Index

- Version: 10.2.0 + Version: 12.1.0 \ No newline at end of file diff -Nru twisted-conch-10.2.0/doc/man/tkconch-man.html twisted-conch-12.1.0/doc/man/tkconch-man.html --- twisted-conch-10.2.0/doc/man/tkconch-man.html 2010-11-30 03:13:25.000000000 +0000 +++ twisted-conch-12.1.0/doc/man/tkconch-man.html 2012-06-04 08:46:24.000000000 +0000 @@ -124,6 +124,6 @@

Index

- Version: 10.2.0 + Version: 12.1.0 \ No newline at end of file diff -Nru twisted-conch-10.2.0/LICENSE twisted-conch-12.1.0/LICENSE --- twisted-conch-10.2.0/LICENSE 2010-01-17 00:03:58.000000000 +0000 +++ twisted-conch-12.1.0/LICENSE 2012-02-11 13:47:35.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2001-2010 +Copyright (c) 2001-2012 Allen Short Andy Gayton Andrew Bennetts @@ -12,7 +12,7 @@ Donovan Preston Eric Mangold Eyal Lotem -Itamar Shtull-Trauring +Itamar Turner-Trauring James Knight Jason A. Mobarak Jean-Paul Calderone diff -Nru twisted-conch-10.2.0/NEWS twisted-conch-12.1.0/NEWS --- twisted-conch-10.2.0/NEWS 2010-11-30 02:27:23.000000000 +0000 +++ twisted-conch-12.1.0/NEWS 2012-06-02 07:04:01.000000000 +0000 @@ -1,6 +1,115 @@ Ticket numbers in this file can be looked up by visiting http://twistedmatrix.com/trac/ticket/ +Twisted Conch 12.1.0 (2012-06-02) +================================= + +Features +-------- + - twisted.conch.tap now supports cred plugins (#4753) + +Bugfixes +-------- + - twisted.conch.client.knownhosts now handles errors encountered + parsing hashed entries in a known hosts file. (#5616) + +Improved Documentation +---------------------- + - Conch examples window.tac and telnet_echo.tac now have better + explanations. (#5590) + +Other +----- + - #5580 + + +Twisted Conch 12.0.0 (2012-02-10) +================================= + +Features +-------- + - use Python shadow module for authentication if it's available + (#3242) + +Bugfixes +-------- + - twisted.conch.ssh.transport.messages no longer ends with with old + message IDs on platforms with differing dict() orderings (#5352) + +Other +----- + - #5225 + + +Twisted Conch 11.1.0 (2011-11-15) +================================= + +Features +-------- + - twisted.conch.ssh.filetransfer.FileTransferClient now handles short + status messages, not strictly allowed by the RFC, but sent by some + SSH implementations. (#3009) + - twisted.conch.manhole now supports CTRL-A and CTRL-E to trigger + HOME and END functions respectively. (#5252) + +Bugfixes +-------- + - When run from an unpacked source tarball or a VCS checkout, the + bin/conch/ scripts will now use the version of Twisted they are + part of. (#3526) + - twisted.conch.insults.window.ScrolledArea now passes no extra + arguments to object.__init__ (which works on more versions of + Python). (#4197) + - twisted.conch.telnet.ITelnetProtocol now has the correct signature + for its unhandledSubnegotiation() method. (#4751) + - twisted.conch.ssh.userauth.SSHUserAuthClient now more closely + follows the RFC 4251 definition of boolean values when negotiating + for key-based authentication, allowing better interoperability with + other SSH implementations. (#5241) + - twisted.conch.recvline.RecvLine now ignores certain function keys + in its keystrokeReceived method instead of raising an exception. + (#5246) + +Deprecations and Removals +------------------------- + - The --user option to `twistd manhole' has been removed as it was + dead code with no functionality associated with it. (#5283) + +Other +----- + - #5107, #5256, #5349 + + +Twisted Conch 11.0.0 (2011-04-01) +================================= + +Bugfixes +-------- + - The transport for subsystem protocols now declares that it + implements ITransport and implements the getHost and getPeer + methods. (#2453) + - twisted.conch.ssh.transport.SSHTransportBase now responds to key + exchange messages at any time during a connection (instead of only + at connection setup). It also queues non-key exchange messages + sent during key exchange to avoid corrupting the connection state. + (#4395) + - Importing twisted.conch.ssh.common no longer breaks pow(base, exp[, + modulus]) when the gmpy package is installed and base is not an + integer. (#4803) + - twisted.conch.ls.lsLine now returns a time string which does not + consider the locale. (#4937) + +Improved Documentation +---------------------- + - Changed the man page for ckeygen to accurately reflect what it + does, and corrected its synposis so that a second "ckeygen" is not + a required part of the ckeygen command line. (#4738) + +Other +----- + - #2112 + + Twisted Conch 10.2.0 (2010-11-29) ================================= diff -Nru twisted-conch-10.2.0/README twisted-conch-12.1.0/README --- twisted-conch-10.2.0/README 2010-11-30 02:27:23.000000000 +0000 +++ twisted-conch-12.1.0/README 2012-06-02 07:04:01.000000000 +0000 @@ -1,4 +1,11 @@ -Twisted Conch 10.2.0 +Twisted Conch 12.1.0 -Conch depends on Python Crypto () -extensions and the pyasn1 module (). +Twisted Conch depends on Twisted Core and on Python Crypto extensions +(). + +The pyasn1 module () is also required. + +gmpy () is strongly recommended to improve +performance. + +Twisted Conch includes a couple simple GUI applications which depend on Tkinter. diff -Nru twisted-conch-10.2.0/setup.py twisted-conch-12.1.0/setup.py --- twisted-conch-10.2.0/setup.py 2009-12-20 19:45:23.000000000 +0000 +++ twisted-conch-12.1.0/setup.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. import sys diff -Nru twisted-conch-10.2.0/twisted/conch/checkers.py twisted-conch-12.1.0/twisted/conch/checkers.py --- twisted-conch-10.2.0/twisted/conch/checkers.py 2010-08-02 18:16:05.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/checkers.py 2011-11-25 01:19:18.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_checkers -*- -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -15,9 +15,15 @@ import crypt try: - # get this from http://www.twistedmatrix.com/users/z3p/files/pyshadow-0.2.tar.gz - import shadow -except: + # Python 2.5 got spwd to interface with shadow passwords + import spwd +except ImportError: + spwd = None + try: + import shadow + except ImportError: + shadow = None +else: shadow = None try: @@ -38,56 +44,92 @@ from twisted.python.filepath import FilePath + def verifyCryptedPassword(crypted, pw): - if crypted[0] == '$': # md5_crypt encrypted - salt = '$1$' + crypted.split('$')[2] + return crypt.crypt(pw, crypted) == crypted + + + +def _pwdGetByName(username): + """ + Look up a user in the /etc/passwd database using the pwd module. If the + pwd module is not available, return None. + + @param username: the username of the user to return the passwd database + information for. + """ + if pwd is None: + return None + return pwd.getpwnam(username) + + + +def _shadowGetByName(username): + """ + Look up a user in the /etc/shadow database using the spwd or shadow + modules. If neither module is available, return None. + + @param username: the username of the user to return the shadow database + information for. + """ + if spwd is not None: + f = spwd.getspnam + elif shadow is not None: + f = shadow.getspnam else: - salt = crypted[:2] - return crypt.crypt(pw, salt) == crypted + return None + return runAsEffectiveUser(0, 0, f, username) + + class UNIXPasswordDatabase: + """ + A checker which validates users out of the UNIX password databases, or + databases of a compatible format. + + @ivar _getByNameFunctions: a C{list} of functions which are called in order + to valid a user. The default value is such that the /etc/passwd + database will be tried first, followed by the /etc/shadow database. + """ credentialInterfaces = IUsernamePassword, implements(ICredentialsChecker) + + def __init__(self, getByNameFunctions=None): + if getByNameFunctions is None: + getByNameFunctions = [_pwdGetByName, _shadowGetByName] + self._getByNameFunctions = getByNameFunctions + + def requestAvatarId(self, credentials): - if pwd: + for func in self._getByNameFunctions: try: - cryptedPass = pwd.getpwnam(credentials.username)[1] + pwnam = func(credentials.username) except KeyError: return defer.fail(UnauthorizedLogin("invalid username")) else: - if cryptedPass not in ['*', 'x'] and \ - verifyCryptedPassword(cryptedPass, credentials.password): - return defer.succeed(credentials.username) - if shadow: - gid = os.getegid() - uid = os.geteuid() - os.setegid(0) - os.seteuid(0) - try: - shadowPass = shadow.getspnam(credentials.username)[1] - except KeyError: - os.setegid(gid) - os.seteuid(uid) - return defer.fail(UnauthorizedLogin("invalid username")) - os.setegid(gid) - os.seteuid(uid) - if verifyCryptedPassword(shadowPass, credentials.password): - return defer.succeed(credentials.username) - return defer.fail(UnauthorizedLogin("invalid password")) - + if pwnam is not None: + crypted = pwnam[1] + if crypted == '': + continue + if verifyCryptedPassword(crypted, credentials.password): + return defer.succeed(credentials.username) + # fallback return defer.fail(UnauthorizedLogin("unable to verify password")) + class SSHPublicKeyDatabase: """ Checker that authenticates SSH public keys, based on public keys listed in authorized_keys and authorized_keys2 files in user .ssh/ directories. """ - - credentialInterfaces = ISSHPrivateKey, implements(ICredentialsChecker) + credentialInterfaces = (ISSHPrivateKey,) + + _userdb = pwd + def requestAvatarId(self, credentials): d = defer.maybeDeferred(self.checkKey, credentials) d.addCallback(self._cbRequestAvatarId, credentials) @@ -146,7 +188,7 @@ @return: A list of L{FilePath} instances to files with the authorized keys. """ - pwent = pwd.getpwnam(credentials.username) + pwent = self._userdb.getpwnam(credentials.username) root = FilePath(pwent.pw_dir).child('.ssh') files = ['authorized_keys', 'authorized_keys2'] return [root.child(f) for f in files] @@ -158,7 +200,7 @@ credentials. """ uid, gid = os.geteuid(), os.getegid() - ouid, ogid = pwd.getpwnam(credentials.username)[2:4] + ouid, ogid = self._userdb.getpwnam(credentials.username)[2:4] for filepath in self.getAuthorizedKeysFiles(credentials): if not filepath.exists(): continue diff -Nru twisted-conch-10.2.0/twisted/conch/client/agent.py twisted-conch-12.1.0/twisted/conch/client/agent.py --- twisted-conch-10.2.0/twisted/conch/client/agent.py 2009-07-02 08:08:13.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/client/agent.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_default -*- -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/client/connect.py twisted-conch-12.1.0/twisted/conch/client/connect.py --- twisted-conch-10.2.0/twisted/conch/client/connect.py 2009-04-26 13:49:56.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/client/connect.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/client/default.py twisted-conch-12.1.0/twisted/conch/client/default.py --- twisted-conch-10.2.0/twisted/conch/client/default.py 2009-07-02 08:08:13.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/client/default.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_knownhosts,twisted.conch.test.test_default -*- -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/client/direct.py twisted-conch-12.1.0/twisted/conch/client/direct.py --- twisted-conch-10.2.0/twisted/conch/client/direct.py 2009-04-26 13:49:56.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/client/direct.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. diff -Nru twisted-conch-10.2.0/twisted/conch/client/__init__.py twisted-conch-12.1.0/twisted/conch/client/__init__.py --- twisted-conch-10.2.0/twisted/conch/client/__init__.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/client/__init__.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/client/knownhosts.py twisted-conch-12.1.0/twisted/conch/client/knownhosts.py --- twisted-conch-10.2.0/twisted/conch/client/knownhosts.py 2010-08-02 18:16:05.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/client/knownhosts.py 2012-04-06 17:20:40.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_knownhosts -*- -# Copyright (c) 2008-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -413,13 +413,13 @@ except IOError: return self for line in fp: - if line.startswith(HashedEntry.MAGIC): - entry = HashedEntry.fromString(line) - else: - try: + try: + if line.startswith(HashedEntry.MAGIC): + entry = HashedEntry.fromString(line) + else: entry = PlainEntry.fromString(line) - except (DecodeError, InvalidEntry, BadKeyError): - entry = UnparsedEntry(line) + except (DecodeError, InvalidEntry, BadKeyError): + entry = UnparsedEntry(line) self._entries.append(entry) return self diff -Nru twisted-conch-10.2.0/twisted/conch/client/options.py twisted-conch-12.1.0/twisted/conch/client/options.py --- twisted-conch-10.2.0/twisted/conch/client/options.py 2009-04-26 13:49:56.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/client/options.py 2011-10-18 10:31:11.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # @@ -29,26 +29,32 @@ ['noagent', 'a', 'Disable authentication agent forwarding (default)'], ['reconnect', 'r', 'Reconnect to the server if the connection is lost.'], ] - zsh_altArgDescr = {"connection-usage":"Connection types to use"} - #zsh_multiUse = ["foo", "bar"] - zsh_mutuallyExclusive = [("agent", "noagent")] - zsh_actions = {"user":"_users", - "ciphers":"_values -s , 'ciphers to choose from' %s" % - " ".join(SSHCiphers.cipherMap.keys()), - "macs":"_values -s , 'macs to choose from' %s" % - " ".join(SSHCiphers.macMap.keys()), - "host-key-algorithms":"_values -s , 'host key algorithms to choose from' %s" % - " ".join(SSHClientTransport.supportedPublicKeys), - #"user-authentications":"_values -s , 'user authentication types to choose from' %s" % - # " ".join(???), - } - #zsh_actionDescr = {"logfile":"log file name", "random":"random seed"} - # user, host, or user@host completion similar to zsh's ssh completion - zsh_extras = ['1:host | user@host:{_ssh;if compset -P "*@"; then _wanted hosts expl "remote host name" _ssh_hosts && ret=0 elif compset -S "@*"; then _wanted users expl "login name" _ssh_users -S "" && ret=0 else if (( $+opt_args[-l] )); then tmp=() else tmp=( "users:login name:_ssh_users -qS@" ) fi; _alternative "hosts:remote host name:_ssh_hosts" "$tmp[@]" && ret=0 fi}'] + + compData = usage.Completions( + mutuallyExclusive=[("agent", "noagent")], + optActions={ + "user": usage.CompleteUsernames(), + "ciphers": usage.CompleteMultiList( + SSHCiphers.cipherMap.keys(), + descr='ciphers to choose from'), + "macs": usage.CompleteMultiList( + SSHCiphers.macMap.keys(), + descr='macs to choose from'), + "host-key-algorithms": usage.CompleteMultiList( + SSHClientTransport.supportedPublicKeys, + descr='host key algorithms to choose from'), + #"user-authentications": usage.CompleteMultiList(? + # descr='user authentication types' ), + }, + extraActions=[usage.CompleteUserAtHost(), + usage.Completer(descr="command"), + usage.Completer(descr='argument', + repeat=True)] + ) def __init__(self, *args, **kw): usage.Options.__init__(self, *args, **kw) - self.identitys = [] + self.identitys = [] self.conns = None def opt_identity(self, i): diff -Nru twisted-conch-10.2.0/twisted/conch/error.py twisted-conch-12.1.0/twisted/conch/error.py --- twisted-conch-10.2.0/twisted/conch/error.py 2008-11-19 14:45:31.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/error.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/__init__.py twisted-conch-12.1.0/twisted/conch/__init__.py --- twisted-conch-10.2.0/twisted/conch/__init__.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/__init__.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/insults/helper.py twisted-conch-12.1.0/twisted/conch/insults/helper.py --- twisted-conch-10.2.0/twisted/conch/insults/helper.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/insults/helper.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_helper -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/insults/insults.py twisted-conch-12.1.0/twisted/conch/insults/insults.py --- twisted-conch-10.2.0/twisted/conch/insults/insults.py 2008-08-16 12:03:30.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/insults/insults.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_insults -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/insults/text.py twisted-conch-12.1.0/twisted/conch/insults/text.py --- twisted-conch-10.2.0/twisted/conch/insults/text.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/insults/text.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_text -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/insults/window.py twisted-conch-12.1.0/twisted/conch/insults/window.py --- twisted-conch-10.2.0/twisted/conch/insults/window.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/insults/window.py 2011-05-15 14:25:06.000000000 +0000 @@ -729,8 +729,12 @@ class ScrolledArea(Widget): + """ + A L{ScrolledArea} contains another widget wrapped in a viewport and + vertical and horizontal scrollbars for moving the viewport around. + """ def __init__(self, containee): - Widget.__init__(self, containee) + Widget.__init__(self) self._viewport = Viewport(containee) self._horiz = HorizontalScrollbar(self._horizScroll) self._vert = VerticalScrollbar(self._vertScroll) diff -Nru twisted-conch-10.2.0/twisted/conch/interfaces.py twisted-conch-12.1.0/twisted/conch/interfaces.py --- twisted-conch-10.2.0/twisted/conch/interfaces.py 2008-11-16 02:54:52.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/interfaces.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/ls.py twisted-conch-12.1.0/twisted/conch/ls.py --- twisted-conch-10.2.0/twisted/conch/ls.py 2008-11-18 13:43:48.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ls.py 2011-03-15 16:35:19.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_cftp -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. import array @@ -7,8 +7,17 @@ from time import time, strftime, localtime +# locale-independent month names to use instead of strftime's +_MONTH_NAMES = dict(zip( + range(1, 13), + "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split())) + def lsLine(name, s): + """ + Build an 'ls' line for a file ('file' in its generic sense, it + can be of any type). + """ mode = s.st_mode perms = array.array('c', '-'*10) ft = stat.S_IFMT(mode) @@ -39,22 +48,28 @@ if mode&stat.S_ISGID: if perms[6] == 'x': perms[6] = 's' else: perms[6] = 'S' - l = perms.tostring() - l += str(s.st_nlink).rjust(5) + ' ' - un = str(s.st_uid) - l += un.ljust(9) - gr = str(s.st_gid) - l += gr.ljust(9) - sz = str(s.st_size) - l += sz.rjust(8) - l += ' ' - sixmo = 60 * 60 * 24 * 7 * 26 - if s.st_mtime + sixmo < time(): # last edited more than 6mo ago - l += strftime("%b %d %Y ", localtime(s.st_mtime)) + + lsresult = [ + perms.tostring(), + str(s.st_nlink).rjust(5), + ' ', + str(s.st_uid).ljust(9), + str(s.st_gid).ljust(9), + str(s.st_size).rjust(8), + ' ', + ] + + # need to specify the month manually, as strftime depends on locale + ttup = localtime(s.st_mtime) + sixmonths = 60 * 60 * 24 * 7 * 26 + if s.st_mtime + sixmonths < time(): # last edited more than 6mo ago + strtime = strftime("%%s %d %Y ", ttup) else: - l += strftime("%b %d %H:%M ", localtime(s.st_mtime)) - l += name - return l + strtime = strftime("%%s %d %H:%M ", ttup) + lsresult.append(strtime % (_MONTH_NAMES[ttup[1]],)) + + lsresult.append(name) + return ''.join(lsresult) __all__ = ['lsLine'] diff -Nru twisted-conch-10.2.0/twisted/conch/manhole.py twisted-conch-12.1.0/twisted/conch/manhole.py --- twisted-conch-10.2.0/twisted/conch/manhole.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/manhole.py 2011-09-19 21:10:30.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_manhole -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -135,6 +135,8 @@ CTRL_D = '\x04' CTRL_BACKSLASH = '\x1c' CTRL_L = '\x0c' +CTRL_A = '\x01' +CTRL_E = '\x05' class Manhole(recvline.HistoricRecvLine): """Mediator between a fancy line source and an interactive interpreter. @@ -159,6 +161,8 @@ self.keyHandlers[CTRL_C] = self.handle_INT self.keyHandlers[CTRL_D] = self.handle_EOF self.keyHandlers[CTRL_L] = self.handle_FF + self.keyHandlers[CTRL_A] = self.handle_HOME + self.keyHandlers[CTRL_E] = self.handle_END self.keyHandlers[CTRL_BACKSLASH] = self.handle_QUIT diff -Nru twisted-conch-10.2.0/twisted/conch/manhole_ssh.py twisted-conch-12.1.0/twisted/conch/manhole_ssh.py --- twisted-conch-10.2.0/twisted/conch/manhole_ssh.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/manhole_ssh.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_manhole -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/manhole_tap.py twisted-conch-12.1.0/twisted/conch/manhole_tap.py --- twisted-conch-10.2.0/twisted/conch/manhole_tap.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/manhole_tap.py 2011-10-01 07:45:02.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -58,12 +58,8 @@ def __init__(self): usage.Options.__init__(self) - self.users = [] self['namespace'] = None - def opt_user(self, name): - self.users.append(name) - def postOptions(self): if self['telnetPort'] is None and self['sshPort'] is None: raise usage.UsageError("At least one of --telnetPort and --sshPort must be specified") diff -Nru twisted-conch-10.2.0/twisted/conch/mixin.py twisted-conch-12.1.0/twisted/conch/mixin.py --- twisted-conch-10.2.0/twisted/conch/mixin.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/mixin.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_mixin -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/openssh_compat/factory.py twisted-conch-12.1.0/twisted/conch/openssh_compat/factory.py --- twisted-conch-10.2.0/twisted/conch/openssh_compat/factory.py 2008-09-02 07:12:21.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/openssh_compat/factory.py 2012-04-07 15:27:45.000000000 +0000 @@ -1,10 +1,10 @@ # -*- test-case-name: twisted.conch.test.test_openssh_compat -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ Factory for reading openssh configuration files: public keys, private keys, and -modile file. +moduli file. """ import os, errno diff -Nru twisted-conch-10.2.0/twisted/conch/openssh_compat/__init__.py twisted-conch-12.1.0/twisted/conch/openssh_compat/__init__.py --- twisted-conch-10.2.0/twisted/conch/openssh_compat/__init__.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/openssh_compat/__init__.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/openssh_compat/primes.py twisted-conch-12.1.0/twisted/conch/openssh_compat/primes.py --- twisted-conch-10.2.0/twisted/conch/openssh_compat/primes.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/openssh_compat/primes.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/recvline.py twisted-conch-12.1.0/twisted/conch/recvline.py --- twisted-conch-10.2.0/twisted/conch/recvline.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/recvline.py 2011-09-02 13:02:18.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_recvline -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -116,6 +116,7 @@ ps = ('>>> ', '... ') pn = 0 + _printableChars = set(string.printable) def connectionMade(self): # A list containing the characters making up the current line @@ -196,7 +197,7 @@ m = self.keyHandlers.get(keyID) if m is not None: m() - elif keyID in string.printable: + elif keyID in self._printableChars: self.characterReceived(keyID, False) else: log.msg("Received unhandled keyID: %r" % (keyID,)) diff -Nru twisted-conch-10.2.0/twisted/conch/scripts/cftp.py twisted-conch-12.1.0/twisted/conch/scripts/cftp.py --- twisted-conch-10.2.0/twisted/conch/scripts/cftp.py 2010-05-30 17:10:42.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/scripts/cftp.py 2011-10-18 10:31:11.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_cftp -*- -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -30,12 +30,12 @@ ['batchfile', 'b', None, 'File to read commands from, or \'-\' for stdin.'], ['requests', 'R', 5, 'Number of requests to make before waiting for a reply.'], ['subsystem', 's', 'sftp', 'Subsystem/server program to connect to.']] - zsh_altArgDescr = {"buffersize":"Size of send/receive buffer (default: 32768)"} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - #zsh_actions = {"foo":'_files -g "*.foo"', "bar":"(one two three)"} - #zsh_actionDescr = {"logfile":"log file name", "random":"random seed"} - zsh_extras = ['2::localfile:{if [[ $words[1] == *:* ]]; then; _files; fi}'] + + compData = usage.Completions( + descriptions={ + "buffersize": "Size of send/receive buffer (default: 32768)"}, + extraActions=[usage.CompleteUserAtHost(), + usage.CompleteFiles(descr="local file")]) def parseArgs(self, host, localPath=None): self['remotePath'] = '' diff -Nru twisted-conch-10.2.0/twisted/conch/scripts/ckeygen.py twisted-conch-12.1.0/twisted/conch/scripts/ckeygen.py --- twisted-conch-10.2.0/twisted/conch/scripts/ckeygen.py 2010-05-30 18:13:04.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/scripts/ckeygen.py 2011-10-18 10:31:11.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_ckeygen -*- -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -37,11 +37,8 @@ ['quiet', 'q', 'Quiet.'], ['showpub', 'y', 'Read private key file and print public key.']] - #zsh_altArgDescr = {"bits":"Number of bits in the key (default: 1024)"} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - zsh_actions = {"type":"(rsa dsa)"} - #zsh_actionDescr = {"logfile":"log file name", "random":"random seed"} + compData = usage.Completions( + optActions={"type": usage.CompleteList(["rsa", "dsa"])}) def run(): options = GeneralOptions() diff -Nru twisted-conch-10.2.0/twisted/conch/scripts/conch.py twisted-conch-12.1.0/twisted/conch/scripts/conch.py --- twisted-conch-10.2.0/twisted/conch/scripts/conch.py 2009-11-20 23:08:39.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/scripts/conch.py 2011-10-18 10:31:11.000000000 +0000 @@ -1,6 +1,6 @@ # -*- test-case-name: twisted.conch.test.test_conch -*- # -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # @@ -37,13 +37,15 @@ ['subsystem', 's', 'Invoke command (mandatory) as SSH2 subsystem.'], ] - #zsh_altArgDescr = {"foo":"use this description for foo instead"} - #zsh_multiUse = ["foo", "bar"] - #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] - #zsh_actions = {"foo":'_files -g "*.foo"', "bar":"(one two three)"} - zsh_actionDescr = {"localforward":"listen-port:host:port", - "remoteforward":"listen-port:host:port"} - zsh_extras = ["*:command: "] + compData = usage.Completions( + mutuallyExclusive=[("tty", "notty")], + optActions={ + "localforward": usage.Completer(descr="listen-port:host:port"), + "remoteforward": usage.Completer(descr="listen-port:host:port")}, + extraActions=[usage.CompleteUserAtHost(), + usage.Completer(descr="command"), + usage.Completer(descr="argument", repeat=True)] + ) localForwards = [] remoteForwards = [] diff -Nru twisted-conch-10.2.0/twisted/conch/scripts/tkconch.py twisted-conch-12.1.0/twisted/conch/scripts/tkconch.py --- twisted-conch-10.2.0/twisted/conch/scripts/tkconch.py 2010-05-30 18:13:04.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/scripts/tkconch.py 2011-10-18 10:31:11.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_scripts -*- -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # @@ -192,7 +192,7 @@ ['localforward', 'L', None, 'listen-port:host:port Forward local port to remote address'], ['remoteforward', 'R', None, 'listen-port:host:port Forward remote port to local address'], ] - + optFlags = [['tty', 't', 'Tty; allocate a tty even if command is given.'], ['notty', 'T', 'Do not allocate a tty.'], ['version', 'V', 'Display version number only.'], @@ -202,16 +202,20 @@ ['log', 'v', 'Log to stderr'], ['ansilog', 'a', 'Print the receieved data to stdout']] - #zsh_altArgDescr = {"foo":"use this description for foo instead"} - #zsh_multiUse = ["foo", "bar"] - zsh_mutuallyExclusive = [("tty", "notty")] - zsh_actions = {"cipher":"(%s)" % " ".join(transport.SSHClientTransport.supportedCiphers), - "macs":"(%s)" % " ".join(transport.SSHClientTransport.supportedMACs)} - zsh_actionDescr = {"localforward":"listen-port:host:port", - "remoteforward":"listen-port:host:port"} - # user, host, or user@host completion similar to zsh's ssh completion - zsh_extras = ['1:host | user@host:{_ssh;if compset -P "*@"; then _wanted hosts expl "remote host name" _ssh_hosts && ret=0 elif compset -S "@*"; then _wanted users expl "login name" _ssh_users -S "" && ret=0 else if (( $+opt_args[-l] )); then tmp=() else tmp=( "users:login name:_ssh_users -qS@" ) fi; _alternative "hosts:remote host name:_ssh_hosts" "$tmp[@]" && ret=0 fi}', - '*:command: '] + _ciphers = transport.SSHClientTransport.supportedCiphers + _macs = transport.SSHClientTransport.supportedMACs + + compData = usage.Completions( + mutuallyExclusive=[("tty", "notty")], + optActions={ + "cipher": usage.CompleteList(_ciphers), + "macs": usage.CompleteList(_macs), + "localforward": usage.Completer(descr="listen-port:host:port"), + "remoteforward": usage.Completer(descr="listen-port:host:port")}, + extraActions=[usage.CompleteUserAtHost(), + usage.Completer(descr="command"), + usage.Completer(descr="argument", repeat=True)] + ) identitys = [] localForwards = [] diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/agent.py twisted-conch-12.1.0/twisted/conch/ssh/agent.py --- twisted-conch-10.2.0/twisted/conch/ssh/agent.py 2009-05-03 19:50:08.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/agent.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/channel.py twisted-conch-12.1.0/twisted/conch/ssh/channel.py --- twisted-conch-10.2.0/twisted/conch/ssh/channel.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/channel.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_channel -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/common.py twisted-conch-12.1.0/twisted/conch/ssh/common.py --- twisted-conch-10.2.0/twisted/conch/ssh/common.py 2010-05-30 18:13:04.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/common.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_ssh -*- -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. @@ -97,14 +97,16 @@ r = pyPow(gmpy.mpz(x),y,z).binary()[::-1] return struct.pack('!L', len(r)) + r -def _fastpow(x, y, z=None): - return pyPow(gmpy.mpz(x), y, z) - def install(): global getMP, MP, _MPpow getMP = _fastgetMP MP = _fastMP _MPpow = _fastMPpow + # XXX: We override builtin pow so that PyCrypto can benefit from gmpy too. + def _fastpow(x, y, z=None, mpz=gmpy.mpz): + if type(x) in (long, int): + x = mpz(x) + return pyPow(x, y, z) __builtins__['pow'] = _fastpow # evil evil try: diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/connection.py twisted-conch-12.1.0/twisted/conch/ssh/connection.py --- twisted-conch-10.2.0/twisted/conch/ssh/connection.py 2010-06-26 18:40:59.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/connection.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_connection -*- -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/factory.py twisted-conch-12.1.0/twisted/conch/ssh/factory.py --- twisted-conch-10.2.0/twisted/conch/ssh/factory.py 2010-06-27 01:49:22.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/factory.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/filetransfer.py twisted-conch-12.1.0/twisted/conch/ssh/filetransfer.py --- twisted-conch-10.2.0/twisted/conch/ssh/filetransfer.py 2009-07-01 15:29:02.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/filetransfer.py 2011-09-09 17:48:29.000000000 +0000 @@ -1,6 +1,6 @@ # -*- test-case-name: twisted.conch.test.test_filetransfer -*- # -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. @@ -708,8 +708,15 @@ d, data = self._parseRequest(data) code, = struct.unpack('!L', data[:4]) data = data[4:] - msg, data = getNS(data) - lang = getNS(data) + if len(data) >= 4: + msg, data = getNS(data) + if len(data) >= 4: + lang, data = getNS(data) + else: + lang = '' + else: + msg = '' + lang = '' if code == FX_OK: d.callback((msg, lang)) elif code == FX_EOF: diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/forwarding.py twisted-conch-12.1.0/twisted/conch/ssh/forwarding.py --- twisted-conch-10.2.0/twisted/conch/ssh/forwarding.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/forwarding.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/__init__.py twisted-conch-12.1.0/twisted/conch/ssh/__init__.py --- twisted-conch-10.2.0/twisted/conch/ssh/__init__.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/__init__.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/keys.py twisted-conch-12.1.0/twisted/conch/ssh/keys.py --- twisted-conch-10.2.0/twisted/conch/ssh/keys.py 2010-05-30 18:13:04.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/keys.py 2011-11-01 21:37:17.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_keys -*- -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -461,9 +461,9 @@ 'RSA' or 'DSA'. """ # the class is Crypto.PublicKey.. - klass = str(self.keyObject.__class__) - if klass.startswith('Crypto.PublicKey'): - type = klass.split('.')[2] + mod = self.keyObject.__class__.__module__ + if mod.startswith('Crypto.PublicKey'): + type = mod.split('.')[2] else: raise RuntimeError('unknown type of object: %r' % self.keyObject) if type in ('RSA', 'DSA'): diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/service.py twisted-conch-12.1.0/twisted/conch/ssh/service.py --- twisted-conch-10.2.0/twisted/conch/ssh/service.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/service.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/session.py twisted-conch-12.1.0/twisted/conch/ssh/session.py --- twisted-conch-10.2.0/twisted/conch/ssh/session.py 2010-03-31 18:58:26.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/session.py 2011-03-15 19:34:33.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_session -*- -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -13,8 +13,9 @@ import signal import sys import os +from zope.interface import implements -from twisted.internet import protocol +from twisted.internet import interfaces, protocol from twisted.python import log from twisted.conch.interfaces import ISession from twisted.conch.ssh import common, channel @@ -181,6 +182,13 @@ class SSHSessionProcessProtocol(protocol.ProcessProtocol): + """I am both an L{IProcessProtocol} and an L{ITransport}. + + I am a transport to the remote endpoint and a process protocol to the + local subsystem. + """ + + implements(interfaces.ITransport) # once initialized, a dictionary mapping signal values to strings # that follow RFC 4254. @@ -267,17 +275,34 @@ struct.pack('>L', err.exitCode)) self.session.loseConnection() - # transport stuff (we are also a transport!) + + def getHost(self): + """ + Return the host from my session's transport. + """ + return self.session.conn.transport.getHost() + + + def getPeer(self): + """ + Return the peer from my session's transport. + """ + return self.session.conn.transport.getPeer() + def write(self, data): self.session.write(data) + def writeSequence(self, seq): self.session.write(''.join(seq)) + def loseConnection(self): self.session.loseConnection() + + class SSHSessionClient(protocol.Protocol): def dataReceived(self, data): diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/sexpy.py twisted-conch-12.1.0/twisted/conch/ssh/sexpy.py --- twisted-conch-10.2.0/twisted/conch/ssh/sexpy.py 2004-08-25 08:36:30.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/sexpy.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/transport.py twisted-conch-12.1.0/twisted/conch/ssh/transport.py --- twisted-conch-10.2.0/twisted/conch/ssh/transport.py 2010-07-08 17:01:47.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/transport.py 2011-11-13 21:36:51.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_transport -*- -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -56,7 +56,7 @@ From RFC 2631, section 2.2:: - X9.42 requires that the private key x be in the interval + X9.42 requires that the private key x be in the interval [2, (q - 2)]. x should be randomly generated in this interval. """ while True: @@ -165,6 +165,20 @@ decrypting data twice, the first bytes are decrypted and stored until the whole packet is available. + @ivar _keyExchangeState: The current protocol state with respect to key + exchange. This is either C{_KEY_EXCHANGE_NONE} if no key exchange is in + progress (and returns to this value after any key exchange completes), + C{_KEY_EXCHANGE_REQUESTED} if this side of the connection initiated a + key exchange, and C{_KEY_EXCHANGE_PROGRESSING} if the other side of the + connection initiated a key exchange. C{_KEY_EXCHANGE_NONE} is the + initial value (however SSH connections begin with key exchange, so it + will quickly change to another state). + + @ivar _blockedByKeyExchange: Whenever C{_keyExchangeState} is not + C{_KEY_EXCHANGE_NONE}, this is a C{list} of pending messages which were + passed to L{sendPacket} but could not be sent because it is not legal to + send them while a key exchange is in progress. When the key exchange + completes, another attempt is made to send these messages. """ @@ -197,6 +211,22 @@ sessionID = None service = None + # There is no key exchange activity in progress. + _KEY_EXCHANGE_NONE = '_KEY_EXCHANGE_NONE' + + # Key exchange is in progress and we started it. + _KEY_EXCHANGE_REQUESTED = '_KEY_EXCHANGE_REQUESTED' + + # Key exchange is in progress and both sides have sent KEXINIT messages. + _KEY_EXCHANGE_PROGRESSING = '_KEY_EXCHANGE_PROGRESSING' + + # There is a fourth conceptual state not represented here: KEXINIT received + # but not sent. Since we always send a KEXINIT as soon as we get it, we + # can't ever be in that state. + + # The current key exchange state. + _keyExchangeState = _KEY_EXCHANGE_NONE + _blockedByKeyExchange = None def connectionLost(self, reason): if self.service: @@ -218,6 +248,20 @@ def sendKexInit(self): + """ + Send a I{KEXINIT} message to initiate key exchange or to respond to a + key exchange initiated by the peer. + + @raise RuntimeError: If a key exchange has already been started and it + is not appropriate to send a I{KEXINIT} message at this time. + + @return: C{None} + """ + if self._keyExchangeState != self._KEY_EXCHANGE_NONE: + raise RuntimeError( + "Cannot send KEXINIT while key exchange state is %r" % ( + self._keyExchangeState,)) + self.ourKexInitPayload = (chr(MSG_KEXINIT) + randbytes.secureRandom(16) + NS(','.join(self.supportedKeyExchanges)) + @@ -232,12 +276,38 @@ NS(','.join(self.supportedLanguages)) + '\000' + '\000\000\000\000') self.sendPacket(MSG_KEXINIT, self.ourKexInitPayload[1:]) + self._keyExchangeState = self._KEY_EXCHANGE_REQUESTED + self._blockedByKeyExchange = [] + + + def _allowedKeyExchangeMessageType(self, messageType): + """ + Determine if the given message type may be sent while key exchange is in + progress. + + @param messageType: The type of message + @type messageType: C{int} + + @return: C{True} if the given type of message may be sent while key + exchange is in progress, C{False} if it may not. + @rtype: C{bool} + + @see: U{http://tools.ietf.org/html/rfc4253#section-7.1} + """ + # Written somewhat peculularly to reflect the way the specification + # defines the allowed message types. + if 1 <= messageType <= 19: + return messageType not in (MSG_SERVICE_REQUEST, MSG_SERVICE_ACCEPT) + if 20 <= messageType <= 29: + return messageType not in (MSG_KEXINIT,) + return 30 <= messageType <= 49 def sendPacket(self, messageType, payload): """ - Sends a packet. If it's been set up, compress the data, encrypt it, - and authenticate it before sending. + Sends a packet. If it's been set up, compress the data, encrypt it, and + authenticate it before sending. If key exchange is in progress and the + message is not part of key exchange, queue it to be sent later. @param messageType: The type of the packet; generally one of the MSG_* values. @@ -245,6 +315,11 @@ @param payload: The payload for the message. @type payload: C{str} """ + if self._keyExchangeState != self._KEY_EXCHANGE_NONE: + if not self._allowedKeyExchangeMessageType(messageType): + self._blockedByKeyExchange.append((messageType, payload)) + return + payload = chr(messageType) + payload if self.outgoingCompression: payload = (self.outgoingCompression.compress(payload) @@ -389,6 +464,20 @@ self.sendUnimplemented() + # Client-initiated rekeying looks like this: + # + # C> MSG_KEXINIT + # S> MSG_KEXINIT + # C> MSG_KEX_DH_GEX_REQUEST or MSG_KEXDH_INIT + # S> MSG_KEX_DH_GEX_GROUP or MSG_KEXDH_REPLY + # C> MSG_KEX_DH_GEX_INIT or -- + # S> MSG_KEX_DH_GEX_REPLY or -- + # C> MSG_NEWKEYS + # S> MSG_NEWKEYS + # + # Server-initiated rekeying is the same, only the first two messages are + # switched. + def ssh_KEXINIT(self, packet): """ Called when we receive a MSG_KEXINIT message. Payload:: @@ -454,6 +543,12 @@ log.msg('incoming: %s %s %s' % (self.nextEncryptions.inCipType, self.nextEncryptions.inMACType, self.incomingCompressionType)) + + if self._keyExchangeState == self._KEY_EXCHANGE_REQUESTED: + self._keyExchangeState = self._KEY_EXCHANGE_PROGRESSING + else: + self.sendKexInit() + return kexAlgs, keyAlgs, rest # for SSHServerTransport to use @@ -617,6 +712,27 @@ self.sendPacket(MSG_NEWKEYS, '') + def _newKeys(self): + """ + Called back by a subclass once a I{MSG_NEWKEYS} message has been + received. This indicates key exchange has completed and new encryption + and compression parameters should be adopted. Any messages which were + queued during key exchange will also be flushed. + """ + log.msg('NEW KEYS') + self.currentEncryptions = self.nextEncryptions + if self.outgoingCompressionType == 'zlib': + self.outgoingCompression = zlib.compressobj(6) + if self.incomingCompressionType == 'zlib': + self.incomingCompression = zlib.decompressobj() + + self._keyExchangeState = self._KEY_EXCHANGE_NONE + messages = self._blockedByKeyExchange + self._blockedByKeyExchange = None + for (messageType, payload) in messages: + self.sendPacket(messageType, payload) + + def isEncrypted(self, direction="out"): """ Return True if the connection is encrypted in the given direction. @@ -741,17 +857,49 @@ self.ignoreNextPacket = True # guess was wrong - def ssh_KEX_DH_GEX_REQUEST_OLD(self, packet): + def _ssh_KEXDH_INIT(self, packet): """ - This represents two different key exchange methods that share the - same integer value. + Called to handle the beginning of a diffie-hellman-group1-sha1 key + exchange. + + Unlike other message types, this is not dispatched automatically. It is + called from C{ssh_KEX_DH_GEX_REQUEST_OLD} because an extra check is + required to determine if this is really a KEXDH_INIT message or if it is + a KEX_DH_GEX_REQUEST_OLD message. - KEXDH_INIT (for diffie-hellman-group1-sha1 exchanges) payload:: + The KEXDH_INIT (for diffie-hellman-group1-sha1 exchanges) payload:: integer e (the client's Diffie-Hellman public key) We send the KEXDH_REPLY with our host key and signature. + """ + clientDHpublicKey, foo = getMP(packet) + y = _getRandomNumber(randbytes.secureRandom, 512) + serverDHpublicKey = _MPpow(DH_GENERATOR, y, DH_PRIME) + sharedSecret = _MPpow(clientDHpublicKey, y, DH_PRIME) + h = sha1() + h.update(NS(self.otherVersionString)) + h.update(NS(self.ourVersionString)) + h.update(NS(self.otherKexInitPayload)) + h.update(NS(self.ourKexInitPayload)) + h.update(NS(self.factory.publicKeys[self.keyAlg].blob())) + h.update(MP(clientDHpublicKey)) + h.update(serverDHpublicKey) + h.update(sharedSecret) + exchangeHash = h.digest() + self.sendPacket( + MSG_KEXDH_REPLY, + NS(self.factory.publicKeys[self.keyAlg].blob()) + + serverDHpublicKey + + NS(self.factory.privateKeys[self.keyAlg].sign(exchangeHash))) + self._keySetup(sharedSecret, exchangeHash) + + def ssh_KEX_DH_GEX_REQUEST_OLD(self, packet): + """ + This represents two different key exchange methods that share the same + integer value. If the message is determined to be a KEXDH_INIT, + C{_ssh_KEXDH_INIT} is called to handle it. Otherwise, for KEX_DH_GEX_REQUEST_OLD (for diffie-hellman-group-exchange-sha1) payload:: @@ -760,34 +908,17 @@ We send the KEX_DH_GEX_GROUP message with the group that is closest in size to ideal. - If we were told to ignore the next key exchange packet by - ssh_KEXINIT, drop it on the floor and return. + If we were told to ignore the next key exchange packet by ssh_KEXINIT, + drop it on the floor and return. """ if self.ignoreNextPacket: self.ignoreNextPacket = 0 return + + # KEXDH_INIT and KEX_DH_GEX_REQUEST_OLD have the same value, so use + # another cue to decide what kind of message the peer sent us. if self.kexAlg == 'diffie-hellman-group1-sha1': - # this is really KEXDH_INIT - clientDHpublicKey, foo = getMP(packet) - y = _getRandomNumber(randbytes.secureRandom, 512) - serverDHpublicKey = _MPpow(DH_GENERATOR, y, DH_PRIME) - sharedSecret = _MPpow(clientDHpublicKey, y, DH_PRIME) - h = sha1() - h.update(NS(self.otherVersionString)) - h.update(NS(self.ourVersionString)) - h.update(NS(self.otherKexInitPayload)) - h.update(NS(self.ourKexInitPayload)) - h.update(NS(self.factory.publicKeys[self.keyAlg].blob())) - h.update(MP(clientDHpublicKey)) - h.update(serverDHpublicKey) - h.update(sharedSecret) - exchangeHash = h.digest() - self.sendPacket( - MSG_KEXDH_REPLY, - NS(self.factory.publicKeys[self.keyAlg].blob()) + - serverDHpublicKey + - NS(self.factory.privateKeys[self.keyAlg].sign(exchangeHash))) - self._keySetup(sharedSecret, exchangeHash) + return self._ssh_KEXDH_INIT(packet) elif self.kexAlg == 'diffie-hellman-group-exchange-sha1': self.dhGexRequest = packet ideal = struct.unpack('>L', packet)[0] @@ -808,8 +939,8 @@ maximum size, and close to ideal if possible. We reply with a MSG_KEX_DH_GEX_GROUP message. - If we were told to ignore the next key exchange packekt by - ssh_KEXINIT, drop it on the floor and return. + If we were told to ignore the next key exchange packet by ssh_KEXINIT, + drop it on the floor and return. """ if self.ignoreNextPacket: self.ignoreNextPacket = 0 @@ -868,16 +999,11 @@ When we get this, the keys have been set on both sides, and we start using them to encrypt and authenticate the connection. """ - log.msg('NEW KEYS') if packet != '': self.sendDisconnect(DISCONNECT_PROTOCOL_ERROR, "NEWKEYS takes no data") return - self.currentEncryptions = self.nextEncryptions - if self.outgoingCompressionType == 'zlib': - self.outgoingCompression = zlib.compressobj(6) - if self.incomingCompressionType == 'zlib': - self.incomingCompression = zlib.decompressobj() + self._newKeys() def ssh_SERVICE_REQUEST(self, packet): @@ -955,17 +1081,40 @@ "to something we don't support") - def ssh_KEX_DH_GEX_GROUP(self, packet): + def _ssh_KEXDH_REPLY(self, packet): """ - This handles two different message which share an integer value. - If the key exchange is diffie-hellman-group1-sha1, this is - MSG_KEXDH_REPLY. Payload:: + Called to handle a reply to a diffie-hellman-group1-sha1 key exchange + message (KEXDH_INIT). + + Like the handler for I{KEXDH_INIT}, this message type has an overlapping + value. This method is called from C{ssh_KEX_DH_GEX_GROUP} if that + method detects a diffie-hellman-group1-sha1 key exchange is in progress. + + Payload:: + string serverHostKey integer f (server Diffie-Hellman public key) string signature We verify the host key by calling verifyHostKey, then continue in _continueKEXDH_REPLY. + """ + pubKey, packet = getNS(packet) + f, packet = getMP(packet) + signature, packet = getNS(packet) + fingerprint = ':'.join([ch.encode('hex') for ch in + md5(pubKey).digest()]) + d = self.verifyHostKey(pubKey, fingerprint) + d.addCallback(self._continueKEXDH_REPLY, pubKey, f, signature) + d.addErrback( + lambda unused: self.sendDisconnect( + DISCONNECT_HOST_KEY_NOT_VERIFIABLE, 'bad host key')) + return d + + + def ssh_KEX_DH_GEX_GROUP(self, packet): + """ + This handles two different message which share an integer value. If the key exchange is diffie-hellman-group-exchange-sha1, this is MSG_KEX_DH_GEX_GROUP. Payload:: @@ -976,18 +1125,7 @@ MSG_KEX_DH_GEX_INIT message. """ if self.kexAlg == 'diffie-hellman-group1-sha1': - # actually MSG_KEXDH_REPLY - pubKey, packet = getNS(packet) - f, packet = getMP(packet) - signature, packet = getNS(packet) - fingerprint = ':'.join([ch.encode('hex') for ch in - md5(pubKey).digest()]) - d = self.verifyHostKey(pubKey, fingerprint) - d.addCallback(self._continueKEXDH_REPLY, pubKey, f, signature) - d.addErrback( - lambda unused: self.sendDisconnect( - DISCONNECT_HOST_KEY_NOT_VERIFIABLE, 'bad host key')) - return d + return self._ssh_KEXDH_REPLY(packet) else: self.p, rest = getMP(packet) self.g, rest = getMP(rest) @@ -1105,12 +1243,7 @@ if not self.nextEncryptions.encBlockSize: self._gotNewKeys = 1 return - log.msg('NEW KEYS') - self.currentEncryptions = self.nextEncryptions - if self.outgoingCompressionType == 'zlib': - self.outgoingCompression = zlib.compressobj(6) - if self.incomingCompressionType == 'zlib': - self.incomingCompression = zlib.decompressobj() + self._newKeys() self.connectionSecure() @@ -1449,5 +1582,10 @@ messages = {} for name, value in globals().items(): - if name.startswith('MSG_'): + # Avoid legacy messages which overlap with never ones + if name.startswith('MSG_') and not name.startswith('MSG_KEXDH_'): messages[value] = name +# Check for regressions (#5352) +if 'MSG_KEXDH_INIT' in messages or 'MSG_KEXDH_REPLY' in messages: + raise RuntimeError( + "legacy SSH mnemonics should not end up in messages dict") diff -Nru twisted-conch-10.2.0/twisted/conch/ssh/userauth.py twisted-conch-12.1.0/twisted/conch/ssh/userauth.py --- twisted-conch-10.2.0/twisted/conch/ssh/userauth.py 2010-03-11 06:37:42.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ssh/userauth.py 2011-08-26 14:19:19.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_userauth -*- -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -564,7 +564,7 @@ publicKey = self.lastPublicKey b = (NS(self.transport.sessionID) + chr(MSG_USERAUTH_REQUEST) + NS(self.user) + NS(self.instance.name) + NS('publickey') + - '\xff' + NS(publicKey.sshType()) + NS(publicKey.blob())) + '\x01' + NS(publicKey.sshType()) + NS(publicKey.blob())) d = self.signData(publicKey, b) if not d: self.askForAuth('none', '') @@ -617,7 +617,7 @@ @type signedData: C{str} """ publicKey = self.lastPublicKey - self.askForAuth('publickey', '\xff' + NS(publicKey.sshType()) + + self.askForAuth('publickey', '\x01' + NS(publicKey.sshType()) + NS(publicKey.blob()) + NS(signedData)) diff -Nru twisted-conch-10.2.0/twisted/conch/stdio.py twisted-conch-12.1.0/twisted/conch/stdio.py --- twisted-conch-10.2.0/twisted/conch/stdio.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/stdio.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_manhole -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/tap.py twisted-conch-12.1.0/twisted/conch/tap.py --- twisted-conch-10.2.0/twisted/conch/tap.py 2010-10-19 01:18:12.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/tap.py 2012-03-12 21:35:11.000000000 +0000 @@ -1,14 +1,15 @@ # -*- test-case-name: twisted.conch.test.test_tap -*- -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ Support module for making SSH servers with twistd. """ -from twisted.conch import checkers, unix +from twisted.conch import unix +from twisted.conch import checkers as conch_checkers from twisted.conch.openssh_compat import factory -from twisted.cred import portal +from twisted.cred import portal, checkers, strcred from twisted.python import usage from twisted.application import strports try: @@ -18,31 +19,69 @@ -class Options(usage.Options): +class Options(usage.Options, strcred.AuthOptionMixin): synopsis = "[-i ] [-p ] [-d ] " - longdesc = "Makes a Conch SSH server." + longdesc = ("Makes a Conch SSH server. If no authentication methods are " + "specified, the default authentication methods are UNIX passwords, " + "SSH public keys, and PAM if it is available. If --auth options are " + "passed, only the measures specified will be used.") optParameters = [ - ["interface", "i", "", "local interface to which we listen"], - ["port", "p", "tcp:22", "Port on which to listen"], - ["data", "d", "/etc", "directory to look for host keys in"], - ["moduli", "", None, "directory to look for moduli in " - "(if different from --data)"] + ["interface", "i", "", "local interface to which we listen"], + ["port", "p", "tcp:22", "Port on which to listen"], + ["data", "d", "/etc", "directory to look for host keys in"], + ["moduli", "", None, "directory to look for moduli in " + "(if different from --data)"] ] - zsh_actions = {"data" : "_dirs", "moduli" : "_dirs"} + compData = usage.Completions( + optActions={"data": usage.CompleteDirs(descr="data directory"), + "moduli": usage.CompleteDirs(descr="moduli directory"), + "interface": usage.CompleteNetInterfaces()} + ) + + + def __init__(self, *a, **kw): + usage.Options.__init__(self, *a, **kw) + + # call the default addCheckers (for backwards compatibility) that will + # be used if no --auth option is provided - note that conch's + # UNIXPasswordDatabase is used, instead of twisted.plugins.cred_unix's + # checker + super(Options, self).addChecker(conch_checkers.UNIXPasswordDatabase()) + super(Options, self).addChecker(conch_checkers.SSHPublicKeyDatabase()) + if pamauth is not None: + super(Options, self).addChecker( + checkers.PluggableAuthenticationModulesChecker()) + + + def addChecker(self, checker): + """ + If addChecker is called, clear out the default checkers first + """ + self['credCheckers'] = [] + self['credInterfaces'] = {} + super(Options, self).addChecker(checker) + def makeService(config): + """ + Construct a service for operating a SSH server. + + @param config: An L{Options} instance specifying server options, including + where server keys are stored and what authentication methods to use. + + @return: An L{IService} provider which contains the requested SSH server. + """ + t = factory.OpenSSHFactory() - t.portal = portal.Portal(unix.UnixSSHRealm()) - t.portal.registerChecker(checkers.UNIXPasswordDatabase()) - t.portal.registerChecker(checkers.SSHPublicKeyDatabase()) - if pamauth is not None: - from twisted.cred.checkers import PluggableAuthenticationModulesChecker - t.portal.registerChecker(PluggableAuthenticationModulesChecker()) + + r = unix.UnixSSHRealm() + t.portal = portal.Portal(r, config.get('credCheckers', [])) t.dataRoot = config['data'] t.moduliRoot = config['moduli'] or config['data'] + port = config['port'] if config['interface']: # Add warning here - port += ':interface='+config['interface'] + port += ':interface=' + config['interface'] return strports.service(port, t) diff -Nru twisted-conch-10.2.0/twisted/conch/telnet.py twisted-conch-12.1.0/twisted/conch/telnet.py --- twisted-conch-10.2.0/twisted/conch/telnet.py 2010-10-18 14:09:30.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/telnet.py 2011-10-01 08:11:41.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_telnet -*- -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -155,10 +155,23 @@ class ITelnetProtocol(iinternet.IProtocol): def unhandledCommand(command, argument): """A command was received but not understood. + + @param command: the command received. + @type command: C{str}, a single character. + @param argument: the argument to the received command. + @type argument: C{str}, a single character, or None if the command that + was unhandled does not provide an argument. """ - def unhandledSubnegotiation(bytes): + def unhandledSubnegotiation(command, bytes): """A subnegotiation command was received but not understood. + + @param command: the command being subnegotiated. That is, the first + byte after the SB command. + @type command: C{str}, a single character. + @param bytes: all other bytes of the subneogation. That is, all but the + first bytes between SB and SE, with IAC un-escaping applied. + @type bytes: C{list} of C{str}, each a single character """ def enableLocal(option): @@ -168,6 +181,9 @@ telnet connection and return True. If False is returned, the option will be treated as still disabled and the peer will be notified. + + @param option: the option to be enabled. + @type option: C{str}, a single character. """ def enableRemote(option): @@ -175,6 +191,9 @@ Returns True if the peer should be allowed to enable this option, False otherwise. + + @param option: the option to be enabled. + @type option: C{str}, a single character. """ def disableLocal(option): @@ -182,10 +201,16 @@ Unlike enableLocal, this method cannot fail. The option must be disabled. + + @param option: the option to be disabled. + @type option: C{str}, a single character. """ def disableRemote(option): """Indicate that the peer has disabled this option. + + @param option: the option to be disabled. + @type option: C{str}, a single character. """ diff -Nru twisted-conch-10.2.0/twisted/conch/test/keydata.py twisted-conch-12.1.0/twisted/conch/test/keydata.py --- twisted-conch-10.2.0/twisted/conch/test/keydata.py 2008-03-08 18:41:56.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/keydata.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_keys -*- -# Copyright (c) 2007-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_agent.py twisted-conch-12.1.0/twisted/conch/test/test_agent.py --- twisted-conch-10.2.0/twisted/conch/test/test_agent.py 2009-07-02 12:42:42.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_agent.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -309,7 +309,7 @@ def _check(sig): # Cannot do this b/c DSA uses random numbers when signing # expected = self.dsaPrivate.sign("John Hancock") - # self.assertEquals(expected, sig) + # self.assertEqual(expected, sig) self.assertTrue(self.dsaPublic.verify(sig, "John Hancock")) return d.addCallback(_check) @@ -340,7 +340,7 @@ received = {} for k in keyt: received[keys.Key.fromString(k[0], type='blob').blob()] = k[1] - self.assertEquals(expected, received) + self.assertEqual(expected, received) return d.addCallback(_check) @@ -395,5 +395,5 @@ self.pump.flush() def _check(ignored): - self.assertEquals(0, len(self.server.factory.keys)) + self.assertEqual(0, len(self.server.factory.keys)) return d.addCallback(_check) diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_cftp.py twisted-conch-12.1.0/twisted/conch/test/test_cftp.py --- twisted-conch-10.2.0/twisted/conch/test/test_cftp.py 2010-05-30 17:10:42.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_cftp.py 2011-07-14 19:05:14.000000000 +0000 @@ -6,6 +6,7 @@ Tests for L{twisted.conch.scripts.cftp}. """ +import locale import time, sys, os, operator, getpass, struct from StringIO import StringIO @@ -142,6 +143,38 @@ '!--------- 0 0 0 0 Aug 29 09:33 foo') + def test_localeIndependent(self): + """ + The month name in the date is locale independent. + """ + # A point about three months in the past. + then = self.now - (60 * 60 * 24 * 31 * 3) + stat = os.stat_result((0, 0, 0, 0, 0, 0, 0, 0, then, 0)) + + # Fake that we're in a language where August is not Aug (e.g.: Spanish) + currentLocale = locale.getlocale() + locale.setlocale(locale.LC_ALL, "es_AR.UTF8") + self.addCleanup(locale.setlocale, locale.LC_ALL, currentLocale) + + self.assertEqual( + self._lsInTimezone('America/New_York', stat), + '!--------- 0 0 0 0 Aug 28 17:33 foo') + self.assertEqual( + self._lsInTimezone('Pacific/Auckland', stat), + '!--------- 0 0 0 0 Aug 29 09:33 foo') + + # if alternate locale is not available, the previous test will be + # skipped, please install this locale for it to run + currentLocale = locale.getlocale() + try: + try: + locale.setlocale(locale.LC_ALL, "es_AR.UTF8") + except locale.Error: + test_localeIndependent.skip = "The es_AR.UTF8 locale is not installed." + finally: + locale.setlocale(locale.LC_ALL, currentLocale) + + def test_newSingleDigitDayOfMonth(self): """ A file with a high-resolution timestamp which falls on a day of the @@ -196,7 +229,7 @@ sys.executable) d = self.client._dispatchCommand("exec print 1 + 2") - d.addCallback(self.assertEquals, "3\n") + d.addCallback(self.assertEqual, "3\n") return d @@ -209,7 +242,7 @@ getpass.getuser(), 'secret', os.getuid(), 1234, 'foo', 'bar', '') d = self.client._dispatchCommand("exec echo hello") - d.addCallback(self.assertEquals, "hello\n") + d.addCallback(self.assertEqual, "hello\n") return d @@ -222,7 +255,7 @@ '/bin/sh') d = self.client._dispatchCommand("!echo hello") - d.addCallback(self.assertEquals, "hello\n") + d.addCallback(self.assertEqual, "hello\n") return d @@ -264,7 +297,7 @@ clock.advance(2.0) wrapper.total += 4096 self.client._printProgressBar(wrapper, startTime) - self.assertEquals(self.client.transport.value(), + self.assertEqual(self.client.transport.value(), "\rsample 40% 4.0kB 2.0kBps 00:03 ") @@ -281,7 +314,7 @@ wrapper = cftp.FileWrapper(wrapped) startTime = clock.seconds() self.client._printProgressBar(wrapper, startTime) - self.assertEquals(self.client.transport.value(), + self.assertEqual(self.client.transport.value(), "\rsample 0% 0.0B 0.0Bps 00:00 ") @@ -582,7 +615,7 @@ """ f1 = file(name1).read() f2 = file(name2).read() - self.failUnlessEqual(f1, f2, msg) + self.assertEqual(f1, f2, msg) def testGet(self): @@ -753,8 +786,8 @@ appropriate error, and doesn't log an useless error server side. """ def _check(results): - self.assertEquals(results[0], '') - self.assertEquals(results[1], + self.assertEqual(results[0], '') + self.assertEqual(results[1], 'remote error 11: mkdir failed') d = self.runScript('mkdir testMakeDirectory', @@ -842,7 +875,7 @@ res = res.split('\n') log.msg('RES %s' % str(res)) self.failUnless(res[1].find(self.testDir) != -1, repr(res)) - self.failUnlessEqual(res[3:-2], ['testDirectory', 'testRemoveFile', + self.assertEqual(res[3:-2], ['testDirectory', 'testRemoveFile', 'testRenameFile', 'testfile1']) d = self._getBatchOutput(cmds) @@ -921,7 +954,7 @@ '-o', 'Port=%i' % (port,), '-b', fn, 'testuser@127.0.0.1') d = getProcessOutputAndValue("sftp", cmds) def check(result): - self.assertEquals(result[2], 0) + self.assertEqual(result[2], 0) for i in ['testDirectory', 'testRemoveFile', 'testRenameFile', 'testfile1']: self.assertIn(i, result[0]) diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_channel.py twisted-conch-12.1.0/twisted/conch/test/test_channel.py --- twisted-conch-10.2.0/twisted/conch/test/test_channel.py 2008-02-19 20:32:40.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_channel.py 2011-07-14 19:05:14.000000000 +0000 @@ -91,31 +91,31 @@ order. """ c = channel.SSHChannel(conn=self.conn) - self.assertEquals(c.localWindowSize, 131072) - self.assertEquals(c.localWindowLeft, 131072) - self.assertEquals(c.localMaxPacket, 32768) - self.assertEquals(c.remoteWindowLeft, 0) - self.assertEquals(c.remoteMaxPacket, 0) - self.assertEquals(c.conn, self.conn) - self.assertEquals(c.data, None) - self.assertEquals(c.avatar, None) + self.assertEqual(c.localWindowSize, 131072) + self.assertEqual(c.localWindowLeft, 131072) + self.assertEqual(c.localMaxPacket, 32768) + self.assertEqual(c.remoteWindowLeft, 0) + self.assertEqual(c.remoteMaxPacket, 0) + self.assertEqual(c.conn, self.conn) + self.assertEqual(c.data, None) + self.assertEqual(c.avatar, None) c2 = channel.SSHChannel(1, 2, 3, 4, 5, 6, 7) - self.assertEquals(c2.localWindowSize, 1) - self.assertEquals(c2.localWindowLeft, 1) - self.assertEquals(c2.localMaxPacket, 2) - self.assertEquals(c2.remoteWindowLeft, 3) - self.assertEquals(c2.remoteMaxPacket, 4) - self.assertEquals(c2.conn, 5) - self.assertEquals(c2.data, 6) - self.assertEquals(c2.avatar, 7) + self.assertEqual(c2.localWindowSize, 1) + self.assertEqual(c2.localWindowLeft, 1) + self.assertEqual(c2.localMaxPacket, 2) + self.assertEqual(c2.remoteWindowLeft, 3) + self.assertEqual(c2.remoteMaxPacket, 4) + self.assertEqual(c2.conn, 5) + self.assertEqual(c2.data, 6) + self.assertEqual(c2.avatar, 7) def test_str(self): """ Test that str(SSHChannel) works gives the channel name and local and remote windows at a glance.. """ - self.assertEquals(str(self.channel), '') def test_logPrefix(self): @@ -123,7 +123,7 @@ Test that SSHChannel.logPrefix gives the name of the channel, the local channel ID and the underlying connection. """ - self.assertEquals(self.channel.logPrefix(), 'SSHChannel channel ' + self.assertEqual(self.channel.logPrefix(), 'SSHChannel channel ' '(unknown) on MockConnection') def test_addWindowBytes(self): @@ -138,13 +138,13 @@ self.channel.write('test') self.channel.writeExtended(1, 'test') self.channel.addWindowBytes(50) - self.assertEquals(self.channel.remoteWindowLeft, 50 - 4 - 4) + self.assertEqual(self.channel.remoteWindowLeft, 50 - 4 - 4) self.assertTrue(self.channel.areWriting) self.assertTrue(cb[0]) - self.assertEquals(self.channel.buf, '') - self.assertEquals(self.conn.data[self.channel], ['test']) - self.assertEquals(self.channel.extBuf, []) - self.assertEquals(self.conn.extData[self.channel], [(1, 'test')]) + self.assertEqual(self.channel.buf, '') + self.assertEqual(self.conn.data[self.channel], ['test']) + self.assertEqual(self.channel.extBuf, []) + self.assertEqual(self.conn.extData[self.channel], [(1, 'test')]) cb[0] = False self.channel.addWindowBytes(20) @@ -192,20 +192,20 @@ self.channel.addWindowBytes(20) self.channel.write('ta') data = self.conn.data[self.channel] - self.assertEquals(data, ['da', 'ta']) - self.assertEquals(self.channel.remoteWindowLeft, 16) + self.assertEqual(data, ['da', 'ta']) + self.assertEqual(self.channel.remoteWindowLeft, 16) # larger than max packet self.channel.write('12345678901') - self.assertEquals(data, ['da', 'ta', '1234567890', '1']) - self.assertEquals(self.channel.remoteWindowLeft, 5) + self.assertEqual(data, ['da', 'ta', '1234567890', '1']) + self.assertEqual(self.channel.remoteWindowLeft, 5) # running out of window cb[0] = False self.channel.write('123456') self.assertFalse(self.channel.areWriting) self.assertTrue(cb[0]) - self.assertEquals(data, ['da', 'ta', '1234567890', '1', '12345']) - self.assertEquals(self.channel.buf, '6') - self.assertEquals(self.channel.remoteWindowLeft, 0) + self.assertEqual(data, ['da', 'ta', '1234567890', '1', '12345']) + self.assertEqual(self.channel.buf, '6') + self.assertEqual(self.channel.remoteWindowLeft, 0) def test_writeExtended(self): """ @@ -227,22 +227,22 @@ self.channel.addWindowBytes(20) self.channel.writeExtended(2, 'a') data = self.conn.extData[self.channel] - self.assertEquals(data, [(1, 'da'), (2, 't'), (2, 'a')]) - self.assertEquals(self.channel.remoteWindowLeft, 16) + self.assertEqual(data, [(1, 'da'), (2, 't'), (2, 'a')]) + self.assertEqual(self.channel.remoteWindowLeft, 16) # larger than max packet self.channel.writeExtended(3, '12345678901') - self.assertEquals(data, [(1, 'da'), (2, 't'), (2, 'a'), + self.assertEqual(data, [(1, 'da'), (2, 't'), (2, 'a'), (3, '1234567890'), (3, '1')]) - self.assertEquals(self.channel.remoteWindowLeft, 5) + self.assertEqual(self.channel.remoteWindowLeft, 5) # running out of window cb[0] = False self.channel.writeExtended(4, '123456') self.assertFalse(self.channel.areWriting) self.assertTrue(cb[0]) - self.assertEquals(data, [(1, 'da'), (2, 't'), (2, 'a'), + self.assertEqual(data, [(1, 'da'), (2, 't'), (2, 'a'), (3, '1234567890'), (3, '1'), (4, '12345')]) - self.assertEquals(self.channel.extBuf, [[4, '6']]) - self.assertEquals(self.channel.remoteWindowLeft, 0) + self.assertEqual(self.channel.extBuf, [[4, '6']]) + self.assertEqual(self.channel.remoteWindowLeft, 0) def test_writeSequence(self): """ @@ -250,7 +250,7 @@ """ self.channel.addWindowBytes(20) self.channel.writeSequence(map(str, range(10))) - self.assertEquals(self.conn.data[self.channel], ['0123456789']) + self.assertEqual(self.conn.data[self.channel], ['0123456789']) def test_loseConnection(self): """ @@ -260,9 +260,9 @@ self.channel.write('data') self.channel.writeExtended(1, 'datadata') self.channel.loseConnection() - self.assertEquals(self.conn.closes.get(self.channel), None) + self.assertEqual(self.conn.closes.get(self.channel), None) self.channel.addWindowBytes(4) # send regular data - self.assertEquals(self.conn.closes.get(self.channel), None) + self.assertEqual(self.conn.closes.get(self.channel), None) self.channel.addWindowBytes(8) # send extended data self.assertTrue(self.conn.closes.get(self.channel)) @@ -270,10 +270,10 @@ """ Test that getPeer() returns ('SSH', ). """ - self.assertEquals(self.channel.getPeer(), ('SSH', 'MockPeer')) + self.assertEqual(self.channel.getPeer(), ('SSH', 'MockPeer')) def test_getHost(self): """ Test that getHost() returns ('SSH', ). """ - self.assertEquals(self.channel.getHost(), ('SSH', 'MockHost')) + self.assertEqual(self.channel.getHost(), ('SSH', 'MockHost')) diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_checkers.py twisted-conch-12.1.0/twisted/conch/test/test_checkers.py --- twisted-conch-10.2.0/twisted/conch/test/test_checkers.py 2010-08-02 18:16:05.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_checkers.py 2011-11-25 01:19:18.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -6,45 +6,182 @@ """ try: - import pwd + import crypt except ImportError: - pwd = None + cryptSkip = 'cannot run without crypt module' +else: + cryptSkip = None import os, base64 +from twisted.python import util +from twisted.python.failure import Failure from twisted.trial.unittest import TestCase from twisted.python.filepath import FilePath from twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse from twisted.cred.credentials import UsernamePassword, IUsernamePassword, \ SSHPrivateKey, ISSHPrivateKey from twisted.cred.error import UnhandledCredentials, UnauthorizedLogin -from twisted.python.fakepwd import UserDatabase +from twisted.python.fakepwd import UserDatabase, ShadowDatabase from twisted.test.test_process import MockOS try: import Crypto.Cipher.DES3 import pyasn1 except ImportError: - SSHPublicKeyDatabase = None + dependencySkip = "can't run without Crypto and PyASN1" else: + dependencySkip = None from twisted.conch.ssh import keys - from twisted.conch.checkers import SSHPublicKeyDatabase, SSHProtocolChecker + from twisted.conch import checkers from twisted.conch.error import NotEnoughAuthentication, ValidPublicKey from twisted.conch.test import keydata +if getattr(os, 'geteuid', None) is None: + euidSkip = "Cannot run without effective UIDs (questionable)" +else: + euidSkip = None + + +class HelperTests(TestCase): + """ + Tests for helper functions L{verifyCryptedPassword}, L{_pwdGetByName} and + L{_shadowGetByName}. + """ + skip = cryptSkip or dependencySkip + + def setUp(self): + self.mockos = MockOS() + + + def test_verifyCryptedPassword(self): + """ + L{verifyCryptedPassword} returns C{True} if the plaintext password + passed to it matches the encrypted password passed to it. + """ + password = 'secret string' + salt = 'salty' + crypted = crypt.crypt(password, salt) + self.assertTrue( + checkers.verifyCryptedPassword(crypted, password), + '%r supposed to be valid encrypted password for %r' % ( + crypted, password)) + + + def test_verifyCryptedPasswordMD5(self): + """ + L{verifyCryptedPassword} returns True if the provided cleartext password + matches the provided MD5 password hash. + """ + password = 'password' + salt = '$1$salt' + crypted = crypt.crypt(password, salt) + self.assertTrue( + checkers.verifyCryptedPassword(crypted, password), + '%r supposed to be valid encrypted password for %s' % ( + crypted, password)) + + + def test_refuteCryptedPassword(self): + """ + L{verifyCryptedPassword} returns C{False} if the plaintext password + passed to it does not match the encrypted password passed to it. + """ + password = 'string secret' + wrong = 'secret string' + crypted = crypt.crypt(password, password) + self.assertFalse( + checkers.verifyCryptedPassword(crypted, wrong), + '%r not supposed to be valid encrypted password for %s' % ( + crypted, wrong)) + + + def test_pwdGetByName(self): + """ + L{_pwdGetByName} returns a tuple of items from the UNIX /etc/passwd + database if the L{pwd} module is present. + """ + userdb = UserDatabase() + userdb.addUser( + 'alice', 'secrit', 1, 2, 'first last', '/foo', '/bin/sh') + self.patch(checkers, 'pwd', userdb) + self.assertEquals( + checkers._pwdGetByName('alice'), userdb.getpwnam('alice')) + + + def test_pwdGetByNameWithoutPwd(self): + """ + If the C{pwd} module isn't present, L{_pwdGetByName} returns C{None}. + """ + self.patch(checkers, 'pwd', None) + self.assertIdentical(checkers._pwdGetByName('alice'), None) + + + def test_shadowGetByName(self): + """ + L{_shadowGetByName} returns a tuple of items from the UNIX /etc/shadow + database if the L{spwd} is present. + """ + userdb = ShadowDatabase() + userdb.addUser('bob', 'passphrase', 1, 2, 3, 4, 5, 6, 7) + self.patch(checkers, 'spwd', userdb) + + self.mockos.euid = 2345 + self.mockos.egid = 1234 + self.patch(checkers, 'os', self.mockos) + self.patch(util, 'os', self.mockos) + + self.assertEquals( + checkers._shadowGetByName('bob'), userdb.getspnam('bob')) + self.assertEquals(self.mockos.seteuidCalls, [0, 2345]) + self.assertEquals(self.mockos.setegidCalls, [0, 1234]) + + + def test_shadowGetByNameWithoutSpwd(self): + """ + L{_shadowGetByName} uses the C{shadow} module to return a tuple of items + from the UNIX /etc/shadow database if the C{spwd} module is not present + and the C{shadow} module is. + """ + userdb = ShadowDatabase() + userdb.addUser('bob', 'passphrase', 1, 2, 3, 4, 5, 6, 7) + self.patch(checkers, 'spwd', None) + self.patch(checkers, 'shadow', userdb) + self.patch(checkers, 'os', self.mockos) + self.patch(util, 'os', self.mockos) + + self.mockos.euid = 2345 + self.mockos.egid = 1234 + + self.assertEquals( + checkers._shadowGetByName('bob'), userdb.getspnam('bob')) + self.assertEquals(self.mockos.seteuidCalls, [0, 2345]) + self.assertEquals(self.mockos.setegidCalls, [0, 1234]) + + + def test_shadowGetByNameWithoutEither(self): + """ + L{_shadowGetByName} returns C{None} if neither C{spwd} nor C{shadow} is + present. + """ + self.patch(checkers, 'spwd', None) + self.patch(checkers, 'shadow', None) + self.patch(checkers, 'os', self.mockos) + + self.assertIdentical(checkers._shadowGetByName('bob'), None) + self.assertEquals(self.mockos.seteuidCalls, []) + self.assertEquals(self.mockos.setegidCalls, []) + + class SSHPublicKeyDatabaseTestCase(TestCase): """ Tests for L{SSHPublicKeyDatabase}. """ - - if pwd is None: - skip = "Cannot run without pwd module" - elif SSHPublicKeyDatabase is None: - skip = "Cannot run without PyCrypto or PyASN1" + skip = euidSkip or dependencySkip def setUp(self): - self.checker = SSHPublicKeyDatabase() + self.checker = checkers.SSHPublicKeyDatabase() self.key1 = base64.encodestring("foobar") self.key2 = base64.encodestring("eggspam") self.content = "t1 %s foo\nt2 %s egg\n" % (self.key1, self.key2) @@ -52,16 +189,16 @@ self.mockos = MockOS() self.mockos.path = FilePath(self.mktemp()) self.mockos.path.makedirs() + self.patch(checkers, 'os', self.mockos) + self.patch(util, 'os', self.mockos) self.sshDir = self.mockos.path.child('.ssh') self.sshDir.makedirs() userdb = UserDatabase() - userdb.addUser('user', 'password', 1, 2, 'first last', - self.mockos.path.path, '/bin/shell') - - self.patch(pwd, "getpwnam", userdb.getpwnam) - self.patch(os, "seteuid", self.mockos.seteuid) - self.patch(os, "setegid", self.mockos.setegid) + userdb.addUser( + 'user', 'password', 1, 2, 'first last', + self.mockos.path.path, '/bin/shell') + self.checker._userdb = userdb def _testCheckKey(self, filename): @@ -81,8 +218,8 @@ authorized_keys file and check the keys against that file. """ self._testCheckKey("authorized_keys") - self.assertEquals(self.mockos.seteuidCalls, []) - self.assertEquals(self.mockos.setegidCalls, []) + self.assertEqual(self.mockos.seteuidCalls, []) + self.assertEqual(self.mockos.setegidCalls, []) def test_checkKey2(self): @@ -91,8 +228,8 @@ authorized_keys2 file and check the keys against that file. """ self._testCheckKey("authorized_keys2") - self.assertEquals(self.mockos.seteuidCalls, []) - self.assertEquals(self.mockos.setegidCalls, []) + self.assertEqual(self.mockos.seteuidCalls, []) + self.assertEqual(self.mockos.setegidCalls, []) def test_checkKeyAsRoot(self): @@ -106,16 +243,20 @@ keyFile.chmod(0000) self.addCleanup(keyFile.chmod, 0777) # And restore the right mode when seteuid is called - savedSeteuid = os.seteuid + savedSeteuid = self.mockos.seteuid def seteuid(euid): keyFile.chmod(0777) return savedSeteuid(euid) - self.patch(os, "seteuid", seteuid) + self.mockos.euid = 2345 + self.mockos.egid = 1234 + self.patch(self.mockos, "seteuid", seteuid) + self.patch(checkers, 'os', self.mockos) + self.patch(util, 'os', self.mockos) user = UsernamePassword("user", "password") user.blob = "foobar" self.assertTrue(self.checker.checkKey(user)) - self.assertEquals(self.mockos.seteuidCalls, [0, 1, 0, os.getuid()]) - self.assertEquals(self.mockos.setegidCalls, [2, os.getgid()]) + self.assertEqual(self.mockos.seteuidCalls, [0, 1, 0, 2345]) + self.assertEqual(self.mockos.setegidCalls, [2, 1234]) def test_requestAvatarId(self): @@ -126,11 +267,12 @@ def _checkKey(ignored): return True self.patch(self.checker, 'checkKey', _checkKey) - credentials = SSHPrivateKey('test', 'ssh-rsa', keydata.publicRSA_openssh, - 'foo', keys.Key.fromString(keydata.privateRSA_openssh).sign('foo')) + credentials = SSHPrivateKey( + 'test', 'ssh-rsa', keydata.publicRSA_openssh, 'foo', + keys.Key.fromString(keydata.privateRSA_openssh).sign('foo')) d = self.checker.requestAvatarId(credentials) def _verify(avatarId): - self.assertEquals(avatarId, 'test') + self.assertEqual(avatarId, 'test') return d.addCallback(_verify) @@ -144,7 +286,8 @@ def _checkKey(ignored): return True self.patch(self.checker, 'checkKey', _checkKey) - credentials = SSHPrivateKey('test', 'ssh-rsa', keydata.publicRSA_openssh, None, None) + credentials = SSHPrivateKey( + 'test', 'ssh-rsa', keydata.publicRSA_openssh, None, None) d = self.checker.requestAvatarId(credentials) return self.assertFailure(d, ValidPublicKey) @@ -170,8 +313,9 @@ def _checkKey(ignored): return True self.patch(self.checker, 'checkKey', _checkKey) - credentials = SSHPrivateKey('test', 'ssh-rsa', keydata.publicRSA_openssh, - 'foo', keys.Key.fromString(keydata.privateDSA_openssh).sign('foo')) + credentials = SSHPrivateKey( + 'test', 'ssh-rsa', keydata.publicRSA_openssh, 'foo', + keys.Key.fromString(keydata.privateDSA_openssh).sign('foo')) d = self.checker.requestAvatarId(credentials) return self.assertFailure(d, UnauthorizedLogin) @@ -194,25 +338,25 @@ return self.assertFailure(d, UnauthorizedLogin) + class SSHProtocolCheckerTestCase(TestCase): """ Tests for L{SSHProtocolChecker}. """ - if SSHPublicKeyDatabase is None: - skip = "Cannot run without PyCrypto" + skip = dependencySkip def test_registerChecker(self): """ L{SSHProcotolChecker.registerChecker} should add the given checker to the list of registered checkers. """ - checker = SSHProtocolChecker() - self.assertEquals(checker.credentialInterfaces, []) - checker.registerChecker(SSHPublicKeyDatabase(), ) - self.assertEquals(checker.credentialInterfaces, [ISSHPrivateKey]) + checker = checkers.SSHProtocolChecker() + self.assertEqual(checker.credentialInterfaces, []) + checker.registerChecker(checkers.SSHPublicKeyDatabase(), ) + self.assertEqual(checker.credentialInterfaces, [ISSHPrivateKey]) self.assertIsInstance(checker.checkers[ISSHPrivateKey], - SSHPublicKeyDatabase) + checkers.SSHPublicKeyDatabase) def test_registerCheckerWithInterface(self): @@ -222,12 +366,13 @@ registered instead of what the checker specifies in credentialIntefaces. """ - checker = SSHProtocolChecker() - self.assertEquals(checker.credentialInterfaces, []) - checker.registerChecker(SSHPublicKeyDatabase(), IUsernamePassword) - self.assertEquals(checker.credentialInterfaces, [IUsernamePassword]) + checker = checkers.SSHProtocolChecker() + self.assertEqual(checker.credentialInterfaces, []) + checker.registerChecker(checkers.SSHPublicKeyDatabase(), + IUsernamePassword) + self.assertEqual(checker.credentialInterfaces, [IUsernamePassword]) self.assertIsInstance(checker.checkers[IUsernamePassword], - SSHPublicKeyDatabase) + checkers.SSHPublicKeyDatabase) def test_requestAvatarId(self): @@ -235,13 +380,13 @@ L{SSHProtocolChecker.requestAvatarId} should defer to one if its registered checkers to authenticate a user. """ - checker = SSHProtocolChecker() + checker = checkers.SSHProtocolChecker() passwordDatabase = InMemoryUsernamePasswordDatabaseDontUse() passwordDatabase.addUser('test', 'test') checker.registerChecker(passwordDatabase) d = checker.requestAvatarId(UsernamePassword('test', 'test')) def _callback(avatarId): - self.assertEquals(avatarId, 'test') + self.assertEqual(avatarId, 'test') return d.addCallback(_callback) @@ -251,7 +396,7 @@ False from _areDone, then L{SSHProtocolChecker} should raise L{NotEnoughAuthentication}. """ - checker = SSHProtocolChecker() + checker = checkers.SSHProtocolChecker() def _areDone(avatarId): return False self.patch(checker, 'areDone', _areDone) @@ -268,7 +413,7 @@ If the passed credentials aren't handled by any registered checker, L{SSHProtocolChecker} should raise L{UnhandledCredentials}. """ - checker = SSHProtocolChecker() + checker = checkers.SSHProtocolChecker() d = checker.requestAvatarId(UsernamePassword('test', 'test')) return self.assertFailure(d, UnhandledCredentials) @@ -277,4 +422,188 @@ """ The default L{SSHProcotolChecker.areDone} should simply return True. """ - self.assertEquals(SSHProtocolChecker().areDone(None), True) + self.assertEquals(checkers.SSHProtocolChecker().areDone(None), True) + + + +class UNIXPasswordDatabaseTests(TestCase): + """ + Tests for L{UNIXPasswordDatabase}. + """ + skip = cryptSkip or dependencySkip + + def assertLoggedIn(self, d, username): + """ + Assert that the L{Deferred} passed in is called back with the value + 'username'. This represents a valid login for this TestCase. + + NOTE: To work, this method's return value must be returned from the + test method, or otherwise hooked up to the test machinery. + + @param d: a L{Deferred} from an L{IChecker.requestAvatarId} method. + @type d: L{Deferred} + @rtype: L{Deferred} + """ + result = [] + d.addBoth(result.append) + self.assertEquals(len(result), 1, "login incomplete") + if isinstance(result[0], Failure): + result[0].raiseException() + self.assertEquals(result[0], username) + + + def test_defaultCheckers(self): + """ + L{UNIXPasswordDatabase} with no arguments has checks the C{pwd} database + and then the C{spwd} database. + """ + checker = checkers.UNIXPasswordDatabase() + + def crypted(username, password): + salt = crypt.crypt(password, username) + crypted = crypt.crypt(password, '$1$' + salt) + return crypted + + pwd = UserDatabase() + pwd.addUser('alice', crypted('alice', 'password'), + 1, 2, 'foo', '/foo', '/bin/sh') + # x and * are convention for "look elsewhere for the password" + pwd.addUser('bob', 'x', 1, 2, 'bar', '/bar', '/bin/sh') + spwd = ShadowDatabase() + spwd.addUser('alice', 'wrong', 1, 2, 3, 4, 5, 6, 7) + spwd.addUser('bob', crypted('bob', 'password'), + 8, 9, 10, 11, 12, 13, 14) + + self.patch(checkers, 'pwd', pwd) + self.patch(checkers, 'spwd', spwd) + + mockos = MockOS() + self.patch(checkers, 'os', mockos) + self.patch(util, 'os', mockos) + + mockos.euid = 2345 + mockos.egid = 1234 + + cred = UsernamePassword("alice", "password") + self.assertLoggedIn(checker.requestAvatarId(cred), 'alice') + self.assertEquals(mockos.seteuidCalls, []) + self.assertEquals(mockos.setegidCalls, []) + cred.username = "bob" + self.assertLoggedIn(checker.requestAvatarId(cred), 'bob') + self.assertEquals(mockos.seteuidCalls, [0, 2345]) + self.assertEquals(mockos.setegidCalls, [0, 1234]) + + + def assertUnauthorizedLogin(self, d): + """ + Asserts that the L{Deferred} passed in is erred back with an + L{UnauthorizedLogin} L{Failure}. This reprsents an invalid login for + this TestCase. + + NOTE: To work, this method's return value must be returned from the + test method, or otherwise hooked up to the test machinery. + + @param d: a L{Deferred} from an L{IChecker.requestAvatarId} method. + @type d: L{Deferred} + @rtype: L{None} + """ + self.assertRaises( + checkers.UnauthorizedLogin, self.assertLoggedIn, d, 'bogus value') + + + def test_passInCheckers(self): + """ + L{UNIXPasswordDatabase} takes a list of functions to check for UNIX + user information. + """ + password = crypt.crypt('secret', 'secret') + userdb = UserDatabase() + userdb.addUser('anybody', password, 1, 2, 'foo', '/bar', '/bin/sh') + checker = checkers.UNIXPasswordDatabase([userdb.getpwnam]) + self.assertLoggedIn( + checker.requestAvatarId(UsernamePassword('anybody', 'secret')), + 'anybody') + + + def test_verifyPassword(self): + """ + If the encrypted password provided by the getpwnam function is valid + (verified by the L{verifyCryptedPassword} function), we callback the + C{requestAvatarId} L{Deferred} with the username. + """ + def verifyCryptedPassword(crypted, pw): + return crypted == pw + def getpwnam(username): + return [username, username] + self.patch(checkers, 'verifyCryptedPassword', verifyCryptedPassword) + checker = checkers.UNIXPasswordDatabase([getpwnam]) + credential = UsernamePassword('username', 'username') + self.assertLoggedIn(checker.requestAvatarId(credential), 'username') + + + def test_failOnKeyError(self): + """ + If the getpwnam function raises a KeyError, the login fails with an + L{UnauthorizedLogin} exception. + """ + def getpwnam(username): + raise KeyError(username) + checker = checkers.UNIXPasswordDatabase([getpwnam]) + credential = UsernamePassword('username', 'username') + self.assertUnauthorizedLogin(checker.requestAvatarId(credential)) + + + def test_failOnBadPassword(self): + """ + If the verifyCryptedPassword function doesn't verify the password, the + login fails with an L{UnauthorizedLogin} exception. + """ + def verifyCryptedPassword(crypted, pw): + return False + def getpwnam(username): + return [username, username] + self.patch(checkers, 'verifyCryptedPassword', verifyCryptedPassword) + checker = checkers.UNIXPasswordDatabase([getpwnam]) + credential = UsernamePassword('username', 'username') + self.assertUnauthorizedLogin(checker.requestAvatarId(credential)) + + + def test_loopThroughFunctions(self): + """ + UNIXPasswordDatabase.requestAvatarId loops through each getpwnam + function associated with it and returns a L{Deferred} which fires with + the result of the first one which returns a value other than None. + ones do not verify the password. + """ + def verifyCryptedPassword(crypted, pw): + return crypted == pw + def getpwnam1(username): + return [username, 'not the password'] + def getpwnam2(username): + return [username, username] + self.patch(checkers, 'verifyCryptedPassword', verifyCryptedPassword) + checker = checkers.UNIXPasswordDatabase([getpwnam1, getpwnam2]) + credential = UsernamePassword('username', 'username') + self.assertLoggedIn(checker.requestAvatarId(credential), 'username') + + + def test_failOnSpecial(self): + """ + If the password returned by any function is C{""}, C{"x"}, or C{"*"} it + is not compared against the supplied password. Instead it is skipped. + """ + pwd = UserDatabase() + pwd.addUser('alice', '', 1, 2, '', 'foo', 'bar') + pwd.addUser('bob', 'x', 1, 2, '', 'foo', 'bar') + pwd.addUser('carol', '*', 1, 2, '', 'foo', 'bar') + self.patch(checkers, 'pwd', pwd) + + checker = checkers.UNIXPasswordDatabase([checkers._pwdGetByName]) + cred = UsernamePassword('alice', '') + self.assertUnauthorizedLogin(checker.requestAvatarId(cred)) + + cred = UsernamePassword('bob', 'x') + self.assertUnauthorizedLogin(checker.requestAvatarId(cred)) + + cred = UsernamePassword('carol', '*') + self.assertUnauthorizedLogin(checker.requestAvatarId(cred)) diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_ckeygen.py twisted-conch-12.1.0/twisted/conch/test/test_ckeygen.py --- twisted-conch-10.2.0/twisted/conch/test/test_ckeygen.py 2009-07-02 12:42:42.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_ckeygen.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_conch.py twisted-conch-12.1.0/twisted/conch/test/test_conch.py --- twisted-conch-10.2.0/twisted/conch/test/test_conch.py 2009-07-20 16:41:45.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_conch.py 2012-01-15 02:23:55.000000000 +0000 @@ -1,15 +1,22 @@ # -*- test-case-name: twisted.conch.test.test_conch -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. import os, sys, socket +from itertools import count + +from zope.interface import implements from twisted.cred import portal from twisted.internet import reactor, defer, protocol from twisted.internet.error import ProcessExitedAlready +from twisted.internet.task import LoopingCall from twisted.python import log, runtime from twisted.trial import unittest from twisted.conch.error import ConchError +from twisted.conch.avatar import ConchUser +from twisted.conch.ssh.session import ISession, SSHSession, wrapProtocol + try: from twisted.conch.scripts.conch import SSHSession as StdioInteractingSession except ImportError, e: @@ -254,25 +261,14 @@ -class ForwardingTestBase: - """ - Template class for tests of the Conch server's ability to forward arbitrary - protocols over SSH. - - These tests are integration tests, not unit tests. They launch a Conch - server, a custom TCP server (just an L{EchoProtocol}) and then call - L{execute}. - - L{execute} is implemented by subclasses of L{ForwardingTestBase}. It should - cause an SSH client to connect to the Conch server, asking it to forward - data to the custom TCP server. - """ - +class ConchServerSetupMixin: if not Crypto: skip = "can't run w/o PyCrypto" if not pyasn1: - skip = "can't run w/o PyASN1" + skip = "Cannot run without PyASN1" + + realmFactory = staticmethod(lambda: ConchTestRealm('testuser')) def _createFiles(self): for f in ['rsa_test','rsa_test.pub','dsa_test','dsa_test.pub', @@ -301,7 +297,7 @@ Make a L{ConchTestServerFactory}, which allows us to start a L{ConchTestServer} -- i.e. an actually listening conch. """ - realm = ConchTestRealm() + realm = self.realmFactory() p = portal.Portal(realm) p.registerChecker(ConchTestPublicKeyChecker()) factory = ConchTestServerFactory() @@ -331,6 +327,21 @@ defer.maybeDeferred(self.echoServer.stopListening)]) + +class ForwardingMixin(ConchServerSetupMixin): + """ + Template class for tests of the Conch server's ability to forward arbitrary + protocols over SSH. + + These tests are integration tests, not unit tests. They launch a Conch + server, a custom TCP server (just an L{EchoProtocol}) and then call + L{execute}. + + L{execute} is implemented by subclasses of L{ForwardingMixin}. It should + cause an SSH client to connect to the Conch server, asking it to forward + data to the custom TCP server. + """ + def test_exec(self): """ Test that we can use whatever client to send the command "echo goodbye" @@ -338,7 +349,7 @@ server. """ d = self.execute('echo goodbye', ConchTestOpenSSHProcess()) - return d.addCallback(self.assertEquals, 'goodbye\n') + return d.addCallback(self.assertEqual, 'goodbye\n') def test_localToRemoteForwarding(self): @@ -370,14 +381,102 @@ -class OpenSSHClientTestCase(ForwardingTestBase, unittest.TestCase): +class RekeyAvatar(ConchUser): + """ + This avatar implements a shell which sends 60 numbered lines to whatever + connects to it, then closes the session with a 0 exit status. + + 60 lines is selected as being enough to send more than 2kB of traffic, the + amount the client is configured to initiate a rekey after. + """ + # Conventionally there is a separate adapter object which provides ISession + # for the user, but making the user provide ISession directly works too. + # This isn't a full implementation of ISession though, just enough to make + # these tests pass. + implements(ISession) + + def __init__(self): + ConchUser.__init__(self) + self.channelLookup['session'] = SSHSession + + + def openShell(self, transport): + """ + Write 60 lines of data to the transport, then exit. + """ + proto = protocol.Protocol() + proto.makeConnection(transport) + transport.makeConnection(wrapProtocol(proto)) + + # Send enough bytes to the connection so that a rekey is triggered in + # the client. + def write(counter): + i = counter() + if i == 60: + call.stop() + transport.session.conn.sendRequest( + transport.session, 'exit-status', '\x00\x00\x00\x00') + transport.loseConnection() + else: + transport.write("line #%02d\n" % (i,)) + # The timing for this loop is an educated guess (and/or the result of + # experimentation) to exercise the case where a packet is generated + # mid-rekey. Since the other side of the connection is (so far) the + # OpenSSH command line client, there's no easy way to determine when the + # rekey has been initiated. If there were, then generating a packet + # immediately at that time would be a better way to test the + # functionality being tested here. + call = LoopingCall(write, count().next) + call.start(0.01) + + + def closed(self): + """ + Ignore the close of the session. + """ + + + +class RekeyRealm: + """ + This realm gives out new L{RekeyAvatar} instances for any avatar request. + """ + def requestAvatar(self, avatarID, mind, *interfaces): + return interfaces[0], RekeyAvatar(), lambda: None + + + +class RekeyTestsMixin(ConchServerSetupMixin): + """ + TestCase mixin which defines tests exercising L{SSHTransportBase}'s handling + of rekeying messages. + """ + realmFactory = RekeyRealm + + def test_clientRekey(self): + """ + After a client-initiated rekey is completed, application data continues + to be passed over the SSH connection. + """ + process = ConchTestOpenSSHProcess() + d = self.execute("", process, '-o RekeyLimit=2K') + def finished(result): + self.assertEqual( + result, + '\n'.join(['line #%02d' % (i,) for i in range(60)]) + '\n') + d.addCallback(finished) + return d + + + +class OpenSSHClientMixin: if not which('ssh'): skip = "no ssh command-line client available" def execute(self, remoteCommand, process, sshArgs=''): """ - Connects to the SSH server started in L{ForwardingTestBase.setUp} by + Connects to the SSH server started in L{ConchServerSetupMixin.setUp} by running the 'ssh' command line tool. @type remoteCommand: str @@ -407,7 +506,26 @@ -class CmdLineClientTestCase(ForwardingTestBase, unittest.TestCase): +class OpenSSHClientForwardingTestCase(ForwardingMixin, OpenSSHClientMixin, + unittest.TestCase): + """ + Connection forwarding tests run against the OpenSSL command line client. + """ + + + +class OpenSSHClientRekeyTestCase(RekeyTestsMixin, OpenSSHClientMixin, + unittest.TestCase): + """ + Rekeying tests run against the OpenSSL command line client. + """ + + + +class CmdLineClientTestCase(ForwardingMixin, unittest.TestCase): + """ + Connection forwarding tests run against the Conch command line client. + """ if runtime.platformType == 'win32': skip = "can't run cmdline client on win32" @@ -432,6 +550,3 @@ env['PYTHONPATH'] = os.pathsep.join(sys.path) reactor.spawnProcess(process, sys.executable, cmds, env=env) return process.deferred - - - diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_connection.py twisted-conch-12.1.0/twisted/conch/test/test_connection.py --- twisted-conch-10.2.0/twisted/conch/test/test_connection.py 2010-06-26 18:40:59.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_connection.py 2011-07-14 19:05:14.000000000 +0000 @@ -235,20 +235,20 @@ messages. """ self.conn.ssh_GLOBAL_REQUEST(common.NS('TestGlobal') + '\xff') - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_REQUEST_SUCCESS, '')]) self.transport.packets = [] self.conn.ssh_GLOBAL_REQUEST(common.NS('TestData') + '\xff' + 'test data') - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_REQUEST_SUCCESS, 'test data')]) self.transport.packets = [] self.conn.ssh_GLOBAL_REQUEST(common.NS('TestBad') + '\xff') - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_REQUEST_FAILURE, '')]) self.transport.packets = [] self.conn.ssh_GLOBAL_REQUEST(common.NS('TestGlobal') + '\x00') - self.assertEquals(self.transport.packets, []) + self.assertEqual(self.transport.packets, []) def test_REQUEST_SUCCESS(self): """ @@ -258,7 +258,7 @@ d = self.conn.sendGlobalRequest('request', 'data', True) self.conn.ssh_REQUEST_SUCCESS('data') def check(data): - self.assertEquals(data, 'data') + self.assertEqual(data, 'data') d.addCallback(check) d.addErrback(self.fail) return d @@ -271,7 +271,7 @@ d = self.conn.sendGlobalRequest('request', 'data', True) self.conn.ssh_REQUEST_FAILURE('data') def check(f): - self.assertEquals(f.value.data, 'data') + self.assertEqual(f.value.data, 'data') d.addCallback(self.fail) d.addErrback(check) return d @@ -285,12 +285,12 @@ self.conn.ssh_CHANNEL_OPEN(common.NS('TestChannel') + '\x00\x00\x00\x01' * 4) self.assertTrue(self.conn.channel.gotOpen) - self.assertEquals(self.conn.channel.conn, self.conn) - self.assertEquals(self.conn.channel.data, '\x00\x00\x00\x01') - self.assertEquals(self.conn.channel.specificData, '\x00\x00\x00\x01') - self.assertEquals(self.conn.channel.remoteWindowLeft, 1) - self.assertEquals(self.conn.channel.remoteMaxPacket, 1) - self.assertEquals(self.transport.packets, + self.assertEqual(self.conn.channel.conn, self.conn) + self.assertEqual(self.conn.channel.data, '\x00\x00\x00\x01') + self.assertEqual(self.conn.channel.specificData, '\x00\x00\x00\x01') + self.assertEqual(self.conn.channel.remoteWindowLeft, 1) + self.assertEqual(self.conn.channel.remoteMaxPacket, 1) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_OPEN_CONFIRMATION, '\x00\x00\x00\x01\x00\x00\x00\x00\x00\x02\x00\x00' '\x00\x00\x80\x00')]) @@ -298,7 +298,7 @@ self.conn.ssh_CHANNEL_OPEN(common.NS('BadChannel') + '\x00\x00\x00\x02' * 4) self.flushLoggedErrors() - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_OPEN_FAILURE, '\x00\x00\x00\x02\x00\x00\x00\x03' + common.NS( 'unknown channel') + common.NS(''))]) @@ -306,7 +306,7 @@ self.conn.ssh_CHANNEL_OPEN(common.NS('ErrorChannel') + '\x00\x00\x00\x02' * 4) self.flushLoggedErrors() - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_OPEN_FAILURE, '\x00\x00\x00\x02\x00\x00\x00\x02' + common.NS( 'unknown failure') + common.NS(''))]) @@ -322,10 +322,10 @@ self.conn.ssh_CHANNEL_OPEN( common.NS('conch-error-args') + '\x00\x00\x00\x01' * 4) errors = self.flushLoggedErrors(error.ConchError) - self.assertEquals( + self.assertEqual( len(errors), 1, "Expected one error, got: %r" % (errors,)) - self.assertEquals(errors[0].value.args, (123, "error args in wrong order")) - self.assertEquals( + self.assertEqual(errors[0].value.args, (123, "error args in wrong order")) + self.assertEqual( self.transport.packets, [(connection.MSG_CHANNEL_OPEN_FAILURE, # The response includes some bytes which identifying the @@ -365,12 +365,12 @@ channel = TestChannel() self.conn.openChannel(channel) self.conn.ssh_CHANNEL_OPEN_CONFIRMATION('\x00\x00\x00\x00'*5) - self.assertEquals(channel.remoteWindowLeft, 0) - self.assertEquals(channel.remoteMaxPacket, 0) - self.assertEquals(channel.specificData, '\x00\x00\x00\x00') - self.assertEquals(self.conn.channelsToRemoteChannel[channel], + self.assertEqual(channel.remoteWindowLeft, 0) + self.assertEqual(channel.remoteMaxPacket, 0) + self.assertEqual(channel.specificData, '\x00\x00\x00\x00') + self.assertEqual(self.conn.channelsToRemoteChannel[channel], 0) - self.assertEquals(self.conn.localToRemoteChannel[0], 0) + self.assertEqual(self.conn.localToRemoteChannel[0], 0) def test_CHANNEL_OPEN_FAILURE(self): """ @@ -381,8 +381,8 @@ self.conn.openChannel(channel) self.conn.ssh_CHANNEL_OPEN_FAILURE('\x00\x00\x00\x00\x00\x00\x00' '\x01' + common.NS('failure!')) - self.assertEquals(channel.openFailureReason.args, ('failure!', 1)) - self.assertEquals(self.conn.channels.get(channel), None) + self.assertEqual(channel.openFailureReason.args, ('failure!', 1)) + self.assertEqual(self.conn.channels.get(channel), None) def test_CHANNEL_WINDOW_ADJUST(self): @@ -395,7 +395,7 @@ oldWindowSize = channel.remoteWindowLeft self.conn.ssh_CHANNEL_WINDOW_ADJUST('\x00\x00\x00\x00\x00\x00\x00' '\x01') - self.assertEquals(channel.remoteWindowLeft, oldWindowSize + 1) + self.assertEqual(channel.remoteWindowLeft, oldWindowSize + 1) def test_CHANNEL_DATA(self): """ @@ -405,23 +405,23 @@ channel = TestChannel(localWindow=6, localMaxPacket=5) self._openChannel(channel) self.conn.ssh_CHANNEL_DATA('\x00\x00\x00\x00' + common.NS('data')) - self.assertEquals(channel.inBuffer, ['data']) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.inBuffer, ['data']) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_WINDOW_ADJUST, '\x00\x00\x00\xff' '\x00\x00\x00\x04')]) self.transport.packets = [] longData = 'a' * (channel.localWindowLeft + 1) self.conn.ssh_CHANNEL_DATA('\x00\x00\x00\x00' + common.NS(longData)) - self.assertEquals(channel.inBuffer, ['data']) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.inBuffer, ['data']) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) channel = TestChannel() self._openChannel(channel) bigData = 'a' * (channel.localMaxPacket + 1) self.transport.packets = [] self.conn.ssh_CHANNEL_DATA('\x00\x00\x00\x01' + common.NS(bigData)) - self.assertEquals(channel.inBuffer, []) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.inBuffer, []) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) def test_CHANNEL_EXTENDED_DATA(self): @@ -433,16 +433,16 @@ self._openChannel(channel) self.conn.ssh_CHANNEL_EXTENDED_DATA('\x00\x00\x00\x00\x00\x00\x00' '\x00' + common.NS('data')) - self.assertEquals(channel.extBuffer, [(0, 'data')]) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.extBuffer, [(0, 'data')]) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_WINDOW_ADJUST, '\x00\x00\x00\xff' '\x00\x00\x00\x04')]) self.transport.packets = [] longData = 'a' * (channel.localWindowLeft + 1) self.conn.ssh_CHANNEL_EXTENDED_DATA('\x00\x00\x00\x00\x00\x00\x00' '\x00' + common.NS(longData)) - self.assertEquals(channel.extBuffer, [(0, 'data')]) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.extBuffer, [(0, 'data')]) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) channel = TestChannel() self._openChannel(channel) @@ -450,8 +450,8 @@ self.transport.packets = [] self.conn.ssh_CHANNEL_EXTENDED_DATA('\x00\x00\x00\x01\x00\x00\x00' '\x00' + common.NS(bigData)) - self.assertEquals(channel.extBuffer, []) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.extBuffer, []) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) def test_CHANNEL_EOF(self): @@ -484,11 +484,11 @@ self._openChannel(channel) self.conn.ssh_CHANNEL_REQUEST('\x00\x00\x00\x00' + common.NS('test') + '\x00') - self.assertEquals(channel.numberRequests, 1) + self.assertEqual(channel.numberRequests, 1) d = self.conn.ssh_CHANNEL_REQUEST('\x00\x00\x00\x00' + common.NS( 'test') + '\xff' + 'data') def check(result): - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_SUCCESS, '\x00\x00\x00\xff')]) d.addCallback(check) return d @@ -502,7 +502,7 @@ d = self.conn.ssh_CHANNEL_REQUEST('\x00\x00\x00\x00' + common.NS( 'test') + '\xff') def check(result): - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_FAILURE, '\x00\x00\x00\xff' )]) d.addCallback(self.fail) @@ -532,7 +532,7 @@ d = self.conn.sendRequest(channel, 'test', '', True) self.conn.ssh_CHANNEL_FAILURE('\x00\x00\x00\x00') def check(result): - self.assertEquals(result.value.value, 'channel request failed') + self.assertEqual(result.value.value, 'channel request failed') d.addCallback(self.fail) d.addErrback(check) return d @@ -545,12 +545,12 @@ # must be added to prevent errbacking during teardown d.addErrback(lambda failure: None) self.conn.sendGlobalRequest('noReply', '', False) - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_GLOBAL_REQUEST, common.NS('wantReply') + '\xffdata'), (connection.MSG_GLOBAL_REQUEST, common.NS('noReply') + '\x00')]) - self.assertEquals(self.conn.deferreds, {'global':[d]}) + self.assertEqual(self.conn.deferreds, {'global':[d]}) def test_openChannel(self): """ @@ -558,11 +558,11 @@ """ channel = TestChannel() self.conn.openChannel(channel, 'aaaa') - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_OPEN, common.NS('TestChannel') + '\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x80\x00aaaa')]) - self.assertEquals(channel.id, 0) - self.assertEquals(self.conn.localChannelID, 1) + self.assertEqual(channel.id, 0) + self.assertEqual(self.conn.localChannelID, 1) def test_sendRequest(self): """ @@ -576,12 +576,12 @@ self.conn.sendRequest(channel, 'test2', '', False) channel.localClosed = True # emulate sending a close message self.conn.sendRequest(channel, 'test3', '', True) - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_REQUEST, '\x00\x00\x00\xff' + common.NS('test') + '\x01test'), (connection.MSG_CHANNEL_REQUEST, '\x00\x00\x00\xff' + common.NS('test2') + '\x00')]) - self.assertEquals(self.conn.deferreds[0], [d]) + self.assertEqual(self.conn.deferreds[0], [d]) def test_adjustWindow(self): """ @@ -592,11 +592,11 @@ self._openChannel(channel) channel.localWindowLeft = 0 self.conn.adjustWindow(channel, 1) - self.assertEquals(channel.localWindowLeft, 1) + self.assertEqual(channel.localWindowLeft, 1) channel.localClosed = True self.conn.adjustWindow(channel, 2) - self.assertEquals(channel.localWindowLeft, 1) - self.assertEquals(self.transport.packets, + self.assertEqual(channel.localWindowLeft, 1) + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_WINDOW_ADJUST, '\x00\x00\x00\xff' '\x00\x00\x00\x01')]) @@ -609,7 +609,7 @@ self.conn.sendData(channel, 'a') channel.localClosed = True self.conn.sendData(channel, 'b') - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_DATA, '\x00\x00\x00\xff' + common.NS('a'))]) @@ -622,7 +622,7 @@ self.conn.sendExtendedData(channel, 1, 'test') channel.localClosed = True self.conn.sendExtendedData(channel, 2, 'test2') - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_EXTENDED_DATA, '\x00\x00\x00\xff' + '\x00\x00\x00\x01' + common.NS('test'))]) @@ -633,11 +633,11 @@ channel = TestChannel() self._openChannel(channel) self.conn.sendEOF(channel) - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_EOF, '\x00\x00\x00\xff')]) channel.localClosed = True self.conn.sendEOF(channel) - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_EOF, '\x00\x00\x00\xff')]) def test_sendClose(self): @@ -648,10 +648,10 @@ self._openChannel(channel) self.conn.sendClose(channel) self.assertTrue(channel.localClosed) - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) self.conn.sendClose(channel) - self.assertEquals(self.transport.packets, + self.assertEqual(self.transport.packets, [(connection.MSG_CHANNEL_CLOSE, '\x00\x00\x00\xff')]) channel2 = TestChannel() @@ -667,9 +667,9 @@ test_CHANNEL_OPEN. """ channel = self.conn.getChannel('TestChannel', 50, 30, 'data') - self.assertEquals(channel.data, 'data') - self.assertEquals(channel.remoteWindowLeft, 50) - self.assertEquals(channel.remoteMaxPacket, 30) + self.assertEqual(channel.data, 'data') + self.assertEqual(channel.remoteWindowLeft, 50) + self.assertEqual(channel.remoteMaxPacket, 30) self.assertRaises(error.ConchError, self.conn.getChannel, 'BadChannel', 50, 30, 'data') @@ -679,7 +679,7 @@ """ del self.transport.avatar self.assertTrue(self.conn.gotGlobalRequest('TestGlobal', 'data')) - self.assertEquals(self.conn.gotGlobalRequest('Test-Data', 'data'), + self.assertEqual(self.conn.gotGlobalRequest('Test-Data', 'data'), (True, 'data')) self.assertFalse(self.conn.gotGlobalRequest('BadGlobal', 'data')) diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_default.py twisted-conch-12.1.0/twisted/conch/test/test_default.py --- twisted-conch-10.2.0/twisted/conch/test/test_default.py 2009-07-02 12:42:42.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_default.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -52,7 +52,7 @@ client.keyAgent = agent cleartext = "Sign here" client.signData(self.rsaPublic, cleartext) - self.assertEquals( + self.assertEqual( transport.value(), "\x00\x00\x00\x8b\r\x00\x00\x00u" + self.rsaPublic.blob() + "\x00\x00\x00\t" + cleartext + @@ -69,9 +69,9 @@ agent = SSHAgentClient() agent.blobs = [self.rsaPublic.blob()] key = agent.getPublicKey() - self.assertEquals(key.isPublic(), True) - self.assertEquals(key, self.rsaPublic) - self.assertEquals(agent.getPublicKey(), None) + self.assertEqual(key.isPublic(), True) + self.assertEqual(key, self.rsaPublic) + self.assertEqual(agent.getPublicKey(), None) def test_getPublicKeyFromFile(self): @@ -84,8 +84,8 @@ options.identitys = [self.rsaFile.path] client = SSHUserAuthClient("user", options, None) key = client.getPublicKey() - self.assertEquals(key.isPublic(), True) - self.assertEquals(key, self.rsaPublic) + self.assertEqual(key.isPublic(), True) + self.assertEqual(key, self.rsaPublic) def test_getPublicKeyAgentFallback(self): @@ -99,8 +99,8 @@ client = SSHUserAuthClient("user", options, None) client.keyAgent = agent key = client.getPublicKey() - self.assertEquals(key.isPublic(), True) - self.assertEquals(key, self.rsaPublic) + self.assertEqual(key.isPublic(), True) + self.assertEqual(key, self.rsaPublic) def test_getPublicKeyBadKeyError(self): @@ -117,9 +117,9 @@ self.tmpdir.child('id_rsa.pub').setContent('not a key!') client = SSHUserAuthClient("user", options, None) key = client.getPublicKey() - self.assertEquals(key.isPublic(), True) - self.assertEquals(key, Key.fromString(keydata.publicDSA_openssh)) - self.assertEquals(client.usedFiles, [self.rsaFile.path, dsaFile.path]) + self.assertEqual(key.isPublic(), True) + self.assertEqual(key, Key.fromString(keydata.publicDSA_openssh)) + self.assertEqual(client.usedFiles, [self.rsaFile.path, dsaFile.path]) def test_getPrivateKey(self): @@ -136,8 +136,8 @@ client.getPublicKey() def _cbGetPrivateKey(key): - self.assertEquals(key.isPublic(), False) - self.assertEquals(key, rsaPrivate) + self.assertEqual(key.isPublic(), False) + self.assertEqual(key, rsaPrivate) return client.getPrivateKey().addCallback(_cbGetPrivateKey) @@ -158,14 +158,14 @@ client.getPublicKey() def _getPassword(prompt): - self.assertEquals(prompt, + self.assertEqual(prompt, "Enter passphrase for key '%s': " % ( self.rsaFile.path,)) return passphrase def _cbGetPrivateKey(key): - self.assertEquals(key.isPublic(), False) - self.assertEquals(key, rsaPrivate) + self.assertEqual(key.isPublic(), False) + self.assertEqual(key, rsaPrivate) self.patch(client, '_getPassword', _getPassword) return client.getPrivateKey().addCallback(_cbGetPrivateKey) diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_filetransfer.py twisted-conch-12.1.0/twisted/conch/test/test_filetransfer.py --- twisted-conch-10.2.0/twisted/conch/test/test_filetransfer.py 2008-11-01 15:32:22.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_filetransfer.py 2011-09-09 17:48:29.000000000 +0000 @@ -147,8 +147,8 @@ def testServerVersion(self): - self.failUnlessEqual(self._serverVersion, 3) - self.failUnlessEqual(self._extData, {'conchTest' : 'ext data'}) + self.assertEqual(self._serverVersion, 3) + self.assertEqual(self._extData, {'conchTest' : 'ext data'}) def test_openedFileClosedWithConnection(self): @@ -173,7 +173,7 @@ self.clientTransport.loseConnection() self.serverTransport.clearBuffer() self.clientTransport.clearBuffer() - self.assertEquals(self.server.openFiles, {}) + self.assertEqual(self.server.openFiles, {}) self.assertIn(fd, closed) d.addCallback(_fileOpened) @@ -193,7 +193,7 @@ self.clientTransport.loseConnection() self.serverTransport.clearBuffer() self.clientTransport.clearBuffer() - self.assertEquals(self.server.openDirs, {}) + self.assertEqual(self.server.openDirs, {}) d.addCallback(_getFiles) return d @@ -205,7 +205,7 @@ self._emptyBuffers() def _fileOpened(openFile): - self.failUnlessEqual(openFile, filetransfer.ISFTPFile(openFile)) + self.assertEqual(openFile, filetransfer.ISFTPFile(openFile)) d = _readChunk(openFile) d.addCallback(_writeChunk, openFile) return d @@ -213,7 +213,7 @@ def _readChunk(openFile): d = openFile.readChunk(0, 20) self._emptyBuffers() - d.addCallback(self.failUnlessEqual, 'a'*10 + 'b'*10) + d.addCallback(self.assertEqual, 'a'*10 + 'b'*10) return d def _writeChunk(_, openFile): @@ -225,7 +225,7 @@ def _readChunk2(_, openFile): d = openFile.readChunk(0, 30) self._emptyBuffers() - d.addCallback(self.failUnlessEqual, 'a'*10 + 'b'*10 + 'c'*10) + d.addCallback(self.assertEqual, 'a'*10 + 'b'*10 + 'c'*10) return d d.addCallback(_fileOpened) @@ -269,7 +269,7 @@ def _getAttrs2(attrs1): d = self.client.getAttrs('testfile1') self._emptyBuffers() - d.addCallback(self.failUnlessEqual, attrs1) + d.addCallback(self.assertEqual, attrs1) return d return d.addCallback(_getAttrs) @@ -293,7 +293,7 @@ d = self.client.setAttrs('testfile1', attrs) self._emptyBuffers() d.addCallback(_getAttrs2) - d.addCallback(self.failUnlessEqual, attrs) + d.addCallback(self.assertEqual, attrs) return d def _getAttrs2(_): @@ -323,7 +323,7 @@ self._emptyBuffers() def check(ign): - self.assertEquals(savedAttributes, {"ext_foo": "bar"}) + self.assertEqual(savedAttributes, {"ext_foo": "bar"}) return d.addCallback(check) @@ -350,7 +350,7 @@ def _testRenamed(_, attrs): d = self.client.getAttrs("testRenamedFile") self._emptyBuffers() - d.addCallback(self.failUnlessEqual, attrs) + d.addCallback(self.assertEqual, attrs) return d.addCallback(_rename) def testDirectoryBad(self): @@ -368,7 +368,7 @@ return d # XXX not until version 4/5 - # self.failUnlessEqual(filetransfer.FILEXFER_TYPE_DIRECTORY&attrs['type'], + # self.assertEqual(filetransfer.FILEXFER_TYPE_DIRECTORY&attrs['type'], # filetransfer.FILEXFER_TYPE_DIRECTORY) def _removeDirectory(_): @@ -400,7 +400,7 @@ def _checkFiles(ignored): fs = list(zip(*files)[0]) fs.sort() - self.failUnlessEqual(fs, + self.assertEqual(fs, ['.testHiddenFile', 'testDirectory', 'testRemoveFile', 'testRenameFile', 'testfile1']) @@ -440,13 +440,13 @@ def _readLink(_): d = self.client.readLink('testLink') self._emptyBuffers() - d.addCallback(self.failUnlessEqual, + d.addCallback(self.assertEqual, os.path.join(os.getcwd(), self.testDir, 'testfile1')) return d def _realPath(_): d = self.client.realPath('testLink') self._emptyBuffers() - d.addCallback(self.failUnlessEqual, + d.addCallback(self.assertEqual, os.path.join(os.getcwd(), self.testDir, 'testfile1')) return d d.addCallback(_readLink) @@ -456,7 +456,7 @@ def testExtendedRequest(self): d = self.client.extendedRequest('testExtendedRequest', 'foo') self._emptyBuffers() - d.addCallback(self.failUnlessEqual, 'bar') + d.addCallback(self.assertEqual, 'bar') d.addCallback(self._cbTestExtendedRequest) return d @@ -675,3 +675,91 @@ len(constants) > 0, "No constants found (the test must be buggy).") for k, v in constants.items(): self.assertEqual(v, getattr(filetransfer, k)) + + + +class TestRawPacketData(unittest.TestCase): + """ + Tests for L{filetransfer.FileTransferClient} which explicitly craft certain + less common protocol messages to exercise their handling. + """ + def setUp(self): + self.ftc = filetransfer.FileTransferClient() + + + def test_packetSTATUS(self): + """ + A STATUS packet containing a result code, a message, and a language is + parsed to produce the result of an outstanding request L{Deferred}. + + @see: U{section 9.1} + of the SFTP Internet-Draft. + """ + d = defer.Deferred() + d.addCallback(self._cbTestPacketSTATUS) + self.ftc.openRequests[1] = d + data = struct.pack('!LL', 1, filetransfer.FX_OK) + common.NS('msg') + common.NS('lang') + self.ftc.packet_STATUS(data) + return d + + + def _cbTestPacketSTATUS(self, result): + """ + Assert that the result is a two-tuple containing the message and + language from the STATUS packet. + """ + self.assertEqual(result[0], 'msg') + self.assertEqual(result[1], 'lang') + + + def test_packetSTATUSShort(self): + """ + A STATUS packet containing only a result code can also be parsed to + produce the result of an outstanding request L{Deferred}. Such packets + are sent by some SFTP implementations, though not strictly legal. + + @see: U{section 9.1} + of the SFTP Internet-Draft. + """ + d = defer.Deferred() + d.addCallback(self._cbTestPacketSTATUSShort) + self.ftc.openRequests[1] = d + data = struct.pack('!LL', 1, filetransfer.FX_OK) + self.ftc.packet_STATUS(data) + return d + + + def _cbTestPacketSTATUSShort(self, result): + """ + Assert that the result is a two-tuple containing empty strings, since + the STATUS packet had neither a message nor a language. + """ + self.assertEqual(result[0], '') + self.assertEqual(result[1], '') + + + def test_packetSTATUSWithoutLang(self): + """ + A STATUS packet containing a result code and a message but no language + can also be parsed to produce the result of an outstanding request + L{Deferred}. Such packets are sent by some SFTP implementations, though + not strictly legal. + + @see: U{section 9.1} + of the SFTP Internet-Draft. + """ + d = defer.Deferred() + d.addCallback(self._cbTestPacketSTATUSWithoutLang) + self.ftc.openRequests[1] = d + data = struct.pack('!LL', 1, filetransfer.FX_OK) + common.NS('msg') + self.ftc.packet_STATUS(data) + return d + + + def _cbTestPacketSTATUSWithoutLang(self, result): + """ + Assert that the result is a two-tuple containing the message from the + STATUS packet and an empty string, since the language was missing. + """ + self.assertEqual(result[0], 'msg') + self.assertEqual(result[1], '') diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_helper.py twisted-conch-12.1.0/twisted/conch/test/test_helper.py --- twisted-conch-10.2.0/twisted/conch/test/test_helper.py 2008-04-22 12:51:57.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_helper.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_helper -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.conch.insults import helper @@ -18,11 +18,11 @@ self.term.connectionMade() def testInitialState(self): - self.assertEquals(self.term.width, WIDTH) - self.assertEquals(self.term.height, HEIGHT) - self.assertEquals(str(self.term), + self.assertEqual(self.term.width, WIDTH) + self.assertEqual(self.term.height, HEIGHT) + self.assertEqual(str(self.term), '\n' * (HEIGHT - 1)) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) + self.assertEqual(self.term.reportCursorPosition(), (0, 0)) def test_initialPrivateModes(self): @@ -94,50 +94,50 @@ def testCursorDown(self): self.term.cursorDown(3) - self.assertEquals(self.term.reportCursorPosition(), (0, 3)) + self.assertEqual(self.term.reportCursorPosition(), (0, 3)) self.term.cursorDown() - self.assertEquals(self.term.reportCursorPosition(), (0, 4)) + self.assertEqual(self.term.reportCursorPosition(), (0, 4)) self.term.cursorDown(HEIGHT) - self.assertEquals(self.term.reportCursorPosition(), (0, HEIGHT - 1)) + self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1)) def testCursorUp(self): self.term.cursorUp(5) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) + self.assertEqual(self.term.reportCursorPosition(), (0, 0)) self.term.cursorDown(20) self.term.cursorUp(1) - self.assertEquals(self.term.reportCursorPosition(), (0, 19)) + self.assertEqual(self.term.reportCursorPosition(), (0, 19)) self.term.cursorUp(19) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) + self.assertEqual(self.term.reportCursorPosition(), (0, 0)) def testCursorForward(self): self.term.cursorForward(2) - self.assertEquals(self.term.reportCursorPosition(), (2, 0)) + self.assertEqual(self.term.reportCursorPosition(), (2, 0)) self.term.cursorForward(2) - self.assertEquals(self.term.reportCursorPosition(), (4, 0)) + self.assertEqual(self.term.reportCursorPosition(), (4, 0)) self.term.cursorForward(WIDTH) - self.assertEquals(self.term.reportCursorPosition(), (WIDTH, 0)) + self.assertEqual(self.term.reportCursorPosition(), (WIDTH, 0)) def testCursorBackward(self): self.term.cursorForward(10) self.term.cursorBackward(2) - self.assertEquals(self.term.reportCursorPosition(), (8, 0)) + self.assertEqual(self.term.reportCursorPosition(), (8, 0)) self.term.cursorBackward(7) - self.assertEquals(self.term.reportCursorPosition(), (1, 0)) + self.assertEqual(self.term.reportCursorPosition(), (1, 0)) self.term.cursorBackward(1) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) + self.assertEqual(self.term.reportCursorPosition(), (0, 0)) self.term.cursorBackward(1) - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) + self.assertEqual(self.term.reportCursorPosition(), (0, 0)) def testCursorPositioning(self): self.term.cursorPosition(3, 9) - self.assertEquals(self.term.reportCursorPosition(), (3, 9)) + self.assertEqual(self.term.reportCursorPosition(), (3, 9)) def testSimpleWriting(self): s = "Hello, world." self.term.write(s) - self.assertEquals( + self.assertEqual( str(self.term), s + '\n' + '\n' * (HEIGHT - 2)) @@ -148,7 +148,7 @@ self.term.cursorBackward(len(s)) self.term.resetModes([modes.IRM]) self.term.write("H") - self.assertEquals( + self.assertEqual( str(self.term), ("H" + s[1:]) + '\n' + '\n' * (HEIGHT - 2)) @@ -159,7 +159,7 @@ self.term.cursorBackward(len(s)) self.term.setModes([modes.IRM]) self.term.write("H") - self.assertEquals( + self.assertEqual( str(self.term), ("H" + s) + '\n' + '\n' * (HEIGHT - 2)) @@ -169,7 +169,7 @@ self.term.cursorDown(5) self.term.cursorForward(5) self.term.write(s) - self.assertEquals( + self.assertEqual( str(self.term), '\n' * 5 + (self.term.fill * 5) + s + '\n' + @@ -179,7 +179,7 @@ s = "Hello, world." self.term.cursorForward(WIDTH - 5) self.term.write(s) - self.assertEquals( + self.assertEqual( str(self.term), s[:5].rjust(WIDTH) + '\n' + s[5:] + '\n' + @@ -187,19 +187,19 @@ def testIndex(self): self.term.index() - self.assertEquals(self.term.reportCursorPosition(), (0, 1)) + self.assertEqual(self.term.reportCursorPosition(), (0, 1)) self.term.cursorDown(HEIGHT) - self.assertEquals(self.term.reportCursorPosition(), (0, HEIGHT - 1)) + self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1)) self.term.index() - self.assertEquals(self.term.reportCursorPosition(), (0, HEIGHT - 1)) + self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1)) def testReverseIndex(self): self.term.reverseIndex() - self.assertEquals(self.term.reportCursorPosition(), (0, 0)) + self.assertEqual(self.term.reportCursorPosition(), (0, 0)) self.term.cursorDown(2) - self.assertEquals(self.term.reportCursorPosition(), (0, 2)) + self.assertEqual(self.term.reportCursorPosition(), (0, 2)) self.term.reverseIndex() - self.assertEquals(self.term.reportCursorPosition(), (0, 1)) + self.assertEqual(self.term.reportCursorPosition(), (0, 1)) def test_nextLine(self): """ @@ -207,45 +207,45 @@ current row. """ self.term.nextLine() - self.assertEquals(self.term.reportCursorPosition(), (0, 1)) + self.assertEqual(self.term.reportCursorPosition(), (0, 1)) self.term.cursorForward(5) - self.assertEquals(self.term.reportCursorPosition(), (5, 1)) + self.assertEqual(self.term.reportCursorPosition(), (5, 1)) self.term.nextLine() - self.assertEquals(self.term.reportCursorPosition(), (0, 2)) + self.assertEqual(self.term.reportCursorPosition(), (0, 2)) def testSaveCursor(self): self.term.cursorDown(5) self.term.cursorForward(7) - self.assertEquals(self.term.reportCursorPosition(), (7, 5)) + self.assertEqual(self.term.reportCursorPosition(), (7, 5)) self.term.saveCursor() self.term.cursorDown(7) self.term.cursorBackward(3) - self.assertEquals(self.term.reportCursorPosition(), (4, 12)) + self.assertEqual(self.term.reportCursorPosition(), (4, 12)) self.term.restoreCursor() - self.assertEquals(self.term.reportCursorPosition(), (7, 5)) + self.assertEqual(self.term.reportCursorPosition(), (7, 5)) def testSingleShifts(self): self.term.singleShift2() self.term.write('Hi') ch = self.term.getCharacter(0, 0) - self.assertEquals(ch[0], 'H') - self.assertEquals(ch[1].charset, G2) + self.assertEqual(ch[0], 'H') + self.assertEqual(ch[1].charset, G2) ch = self.term.getCharacter(1, 0) - self.assertEquals(ch[0], 'i') - self.assertEquals(ch[1].charset, G0) + self.assertEqual(ch[0], 'i') + self.assertEqual(ch[1].charset, G0) self.term.singleShift3() self.term.write('!!') ch = self.term.getCharacter(2, 0) - self.assertEquals(ch[0], '!') - self.assertEquals(ch[1].charset, G3) + self.assertEqual(ch[0], '!') + self.assertEqual(ch[1].charset, G3) ch = self.term.getCharacter(3, 0) - self.assertEquals(ch[0], '!') - self.assertEquals(ch[1].charset, G0) + self.assertEqual(ch[0], '!') + self.assertEqual(ch[1].charset, G0) def testShifting(self): s1 = "Hello" @@ -262,8 +262,8 @@ for s in (s1, s2, s3): for i in range(len(s)): ch = self.term.getCharacter(i, h) - self.assertEquals(ch[0], s[i]) - self.assertEquals(ch[1].charset, g) + self.assertEqual(ch[0], s[i]) + self.assertEqual(ch[1].charset, g) g = g == G0 and G1 or G0 h += 1 @@ -278,28 +278,28 @@ self.term.write('Z') ch = self.term.getCharacter(0, 0) - self.assertEquals(ch[0], 'W') + self.assertEqual(ch[0], 'W') self.failUnless(ch[1].bold) self.failUnless(ch[1].underline) self.failUnless(ch[1].blink) self.failUnless(ch[1].reverseVideo) ch = self.term.getCharacter(1, 0) - self.assertEquals(ch[0], 'X') + self.assertEqual(ch[0], 'X') self.failIf(ch[1].bold) self.failIf(ch[1].underline) self.failIf(ch[1].blink) self.failIf(ch[1].reverseVideo) ch = self.term.getCharacter(2, 0) - self.assertEquals(ch[0], 'Y') + self.assertEqual(ch[0], 'Y') self.failUnless(ch[1].blink) self.failIf(ch[1].bold) self.failIf(ch[1].underline) self.failIf(ch[1].reverseVideo) ch = self.term.getCharacter(3, 0) - self.assertEquals(ch[0], 'Z') + self.assertEqual(ch[0], 'Z') self.failUnless(ch[1].blink) self.failUnless(ch[1].bold) self.failIf(ch[1].underline) @@ -316,25 +316,25 @@ for i in range(len(s1)): ch = self.term.getCharacter(i, 0) - self.assertEquals(ch[0], s1[i]) - self.assertEquals(ch[1].charset, G0) - self.assertEquals(ch[1].bold, False) - self.assertEquals(ch[1].underline, False) - self.assertEquals(ch[1].blink, False) - self.assertEquals(ch[1].reverseVideo, False) - self.assertEquals(ch[1].foreground, helper.RED) - self.assertEquals(ch[1].background, helper.GREEN) + self.assertEqual(ch[0], s1[i]) + self.assertEqual(ch[1].charset, G0) + self.assertEqual(ch[1].bold, False) + self.assertEqual(ch[1].underline, False) + self.assertEqual(ch[1].blink, False) + self.assertEqual(ch[1].reverseVideo, False) + self.assertEqual(ch[1].foreground, helper.RED) + self.assertEqual(ch[1].background, helper.GREEN) for i in range(len(s2)): ch = self.term.getCharacter(i, 1) - self.assertEquals(ch[0], s2[i]) - self.assertEquals(ch[1].charset, G0) - self.assertEquals(ch[1].bold, False) - self.assertEquals(ch[1].underline, False) - self.assertEquals(ch[1].blink, False) - self.assertEquals(ch[1].reverseVideo, False) - self.assertEquals(ch[1].foreground, helper.WHITE) - self.assertEquals(ch[1].background, helper.BLACK) + self.assertEqual(ch[0], s2[i]) + self.assertEqual(ch[1].charset, G0) + self.assertEqual(ch[1].bold, False) + self.assertEqual(ch[1].underline, False) + self.assertEqual(ch[1].blink, False) + self.assertEqual(ch[1].reverseVideo, False) + self.assertEqual(ch[1].foreground, helper.WHITE) + self.assertEqual(ch[1].background, helper.BLACK) def testEraseLine(self): s1 = 'line 1' @@ -344,7 +344,7 @@ self.term.cursorPosition(1, 1) self.term.eraseLine() - self.assertEquals( + self.assertEqual( str(self.term), s1 + '\n' + '\n' + @@ -356,7 +356,7 @@ self.term.write(s) self.term.cursorBackward(5) self.term.eraseToLineEnd() - self.assertEquals( + self.assertEqual( str(self.term), s[:-5] + '\n' + '\n' * (HEIGHT - 2)) @@ -366,7 +366,7 @@ self.term.write(s) self.term.cursorBackward(5) self.term.eraseToLineBeginning() - self.assertEquals( + self.assertEqual( str(self.term), s[-4:].rjust(len(s)) + '\n' + '\n' * (HEIGHT - 2)) @@ -376,7 +376,7 @@ self.term.write('Goodbye world\n') self.term.eraseDisplay() - self.assertEquals( + self.assertEqual( str(self.term), '\n' * (HEIGHT - 1)) @@ -387,7 +387,7 @@ self.term.cursorPosition(5, 1) self.term.eraseToDisplayEnd() - self.assertEquals( + self.assertEqual( str(self.term), s1 + '\n' + s2[:5] + '\n' + @@ -400,7 +400,7 @@ self.term.cursorPosition(5, 1) self.term.eraseToDisplayBeginning() - self.assertEquals( + self.assertEqual( str(self.term), '\n' + s2[6:].rjust(len(s2)) + '\n' + @@ -413,7 +413,7 @@ self.term.cursorPosition(7, 1) self.term.insertLine() - self.assertEquals( + self.assertEqual( str(self.term), s1 + '\n' + '\n' + @@ -428,7 +428,7 @@ self.term.cursorPosition(9, 1) self.term.deleteLine() - self.assertEquals( + self.assertEqual( str(self.term), s1 + '\n' + s3 + '\n' + @@ -478,8 +478,8 @@ self.failIf(result) self.term.write("hello world\n") self.failUnless(result) - self.assertEquals(result[0].group(), "hello world") - self.assertEquals(len(self.fs.calls), 1) + self.assertEqual(result[0].group(), "hello world") + self.assertEqual(len(self.fs.calls), 1) self.failIf(self.fs.calls[0].active()) def testBrokenUpString(self): @@ -494,7 +494,7 @@ self.failIf(result) self.term.write("d") self.failUnless(result) - self.assertEquals(result[0].group(), "hello world") + self.assertEqual(result[0].group(), "hello world") def testMultiple(self): @@ -508,11 +508,11 @@ self.term.write("hello") self.failIf(result) self.term.write(" ") - self.assertEquals(len(result), 1) + self.assertEqual(len(result), 1) self.term.write("world") - self.assertEquals(len(result), 2) - self.assertEquals(result[0].group(), "hello ") - self.assertEquals(result[1].group(), "world") + self.assertEqual(len(result), 2) + self.assertEqual(result[0].group(), "hello ") + self.assertEqual(result[1].group(), "world") def testSynchronous(self): self.term.write("hello world") @@ -521,7 +521,7 @@ d = self.term.expect("hello world") d.addCallback(result.append) self.failUnless(result) - self.assertEquals(result[0].group(), "hello world") + self.assertEqual(result[0].group(), "hello world") def testMultipleSynchronous(self): self.term.write("goodbye world") @@ -532,9 +532,9 @@ d2 = self.term.expect("world") d2.addCallback(result.append) - self.assertEquals(len(result), 2) - self.assertEquals(result[0].group(), "bye") - self.assertEquals(result[1].group(), "world") + self.assertEqual(len(result), 2) + self.assertEqual(result[0].group(), "bye") + self.assertEqual(result[1].group(), "world") def _cbTestTimeoutFailure(self, res): self.assert_(hasattr(res, 'type')) @@ -556,5 +556,5 @@ self.fs.calls[0].call() - self.assertEquals(len(result), 1) - self.assertEquals(result[0].group(), "zoom") + self.assertEqual(len(result), 1) + self.assertEqual(result[0].group(), "zoom") diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_insults.py twisted-conch-12.1.0/twisted/conch/test/test_insults.py --- twisted-conch-10.2.0/twisted/conch/test/test_insults.py 2010-07-13 21:12:58.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_insults.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_insults -*- -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.trial import unittest @@ -61,12 +61,12 @@ def assertCall(self, occurrence, methodName, expectedPositionalArgs=(), expectedKeywordArgs={}): attr, mock = occurrence - self.assertEquals(attr, methodName) - self.assertEquals(len(occurrences(mock)), 1) + self.assertEqual(attr, methodName) + self.assertEqual(len(occurrences(mock)), 1) [(call, result, args, kw)] = occurrences(mock) - self.assertEquals(call, "__call__") - self.assertEquals(args, expectedPositionalArgs) - self.assertEquals(kw, expectedKeywordArgs) + self.assertEqual(call, "__call__") + self.assertEqual(args, expectedPositionalArgs) + self.assertEqual(kw, expectedKeywordArgs) return result @@ -95,7 +95,7 @@ def verifyResults(self, transport, proto, parser): result = self.assertCall(occurrences(proto).pop(0), "makeConnection", (parser,)) - self.assertEquals(occurrences(result), []) + self.assertEqual(occurrences(result), []) del _byteGroupingTestTemplate @@ -111,7 +111,7 @@ for arrow in (parser.UP_ARROW, parser.DOWN_ARROW, parser.RIGHT_ARROW, parser.LEFT_ARROW): result = self.assertCall(occurrences(proto).pop(0), "keystrokeReceived", (arrow, None)) - self.assertEquals(occurrences(result), []) + self.assertEqual(occurrences(result), []) self.failIf(occurrences(proto)) @@ -128,11 +128,11 @@ for char in 'abc123ABC!@#': result = self.assertCall(occurrences(proto).pop(0), "keystrokeReceived", (char, None)) - self.assertEquals(occurrences(result), []) + self.assertEqual(occurrences(result), []) for char in 'abc123': result = self.assertCall(occurrences(proto).pop(0), "keystrokeReceived", (char, parser.ALT)) - self.assertEquals(occurrences(result), []) + self.assertEqual(occurrences(result), []) occs = occurrences(proto) self.failIf(occs, "%r should have been []" % (occs,)) @@ -155,7 +155,7 @@ for funcNum in range(1, 13): funcArg = getattr(parser, 'F%d' % (funcNum,)) result = self.assertCall(occurrences(proto).pop(0), "keystrokeReceived", (funcArg, None)) - self.assertEquals(occurrences(result), []) + self.assertEqual(occurrences(result), []) self.failIf(occurrences(proto)) class ClientCursorMovement(ByteGroupingsMixin, unittest.TestCase): @@ -175,7 +175,7 @@ for (method, count) in [('Down', 2), ('Forward', 4), ('Up', 1), ('Backward', 2), ('Up', 1), ('Backward', 2)]: result = self.assertCall(occurrences(proto).pop(0), "cursor" + method, (count,)) - self.assertEquals(occurrences(result), []) + self.assertEqual(occurrences(result), []) self.failIf(occurrences(proto)) class ClientControlSequences(unittest.TestCase, MockMixin): @@ -354,13 +354,13 @@ def testCursorPosition(self): methods(self.proto)['reportCursorPosition'] = (6, 7) self.parser.dataReceived("\x1b[6n") - self.assertEquals(self.transport.value(), "\x1b[7;8R") + self.assertEqual(self.transport.value(), "\x1b[7;8R") occs = occurrences(self.proto) result = self.assertCall(occs.pop(0), "reportCursorPosition") # This isn't really an interesting assert, since it only tests that # our mock setup is working right, but I'll include it anyway. - self.assertEquals(result, (6, 7)) + self.assertEqual(result, (6, 7)) def test_applicationDataBytes(self): @@ -472,8 +472,8 @@ """ warnings = self.flushWarnings() self.assertIdentical(warnings[0]['category'], DeprecationWarning) - self.assertEquals(warnings[0]['message'], message) - self.assertEquals(len(warnings), 1) + self.assertEqual(warnings[0]['message'], message) + self.assertEqual(len(warnings), 1) def test_colors(self): diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_keys.py twisted-conch-12.1.0/twisted/conch/test/test_keys.py --- twisted-conch-10.2.0/twisted/conch/test/test_keys.py 2010-05-30 18:13:04.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_keys.py 2012-01-15 02:23:55.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -31,7 +31,7 @@ if Crypto is None: skip = "cannot run w/o PyCrypto" if pyasn1 is None: - skip = "cannot run w/o/ PyASN1" + skip = "Cannot run without PyASN1" def setUp(self): self._secureRandom = randbytes.secureRandom @@ -47,11 +47,11 @@ """ data = 'ABC' messageSize = 6 - self.assertEquals(keys.pkcs1Pad(data, messageSize), + self.assertEqual(keys.pkcs1Pad(data, messageSize), '\x01\xff\x00ABC') hash = sha1().digest() messageSize = 40 - self.assertEquals(keys.pkcs1Digest('', messageSize), + self.assertEqual(keys.pkcs1Digest('', messageSize), '\x01\xff\xff\xff\x00' + keys.ID_SHA1 + hash) def _signRSA(self, data): @@ -72,7 +72,7 @@ key, sig = self._signRSA(data) sigData = keys.pkcs1Digest(data, keys.lenSig(key)) v = key.sign(sigData, '')[0] - self.assertEquals(sig, common.NS('ssh-rsa') + common.MP(v)) + self.assertEqual(sig, common.NS('ssh-rsa') + common.MP(v)) return key, sig def test_signDSA(self): @@ -83,7 +83,7 @@ key, sig = self._signDSA(data) sigData = sha1(data).digest() v = key.sign(sigData, '\x55' * 19) - self.assertEquals(sig, common.NS('ssh-dss') + common.NS( + self.assertEqual(sig, common.NS('ssh-dss') + common.NS( Crypto.Util.number.long_to_bytes(v[0], 20) + Crypto.Util.number.long_to_bytes(v[1], 20))) return key, sig @@ -93,9 +93,9 @@ """ Test that objectType, returns the correct type for objects. """ - self.assertEquals(keys.objectType(keys.Key.fromString( + self.assertEqual(keys.objectType(keys.Key.fromString( keydata.privateRSA_openssh).keyObject), 'ssh-rsa') - self.assertEquals(keys.objectType(keys.Key.fromString( + self.assertEqual(keys.objectType(keys.Key.fromString( keydata.privateDSA_openssh).keyObject), 'ssh-dss') self.assertRaises(keys.BadKeyError, keys.objectType, None) @@ -105,7 +105,7 @@ if Crypto is None: skip = "cannot run w/o PyCrypto" if pyasn1 is None: - skip = "cannot run w/o/ PyASN1" + skip = "Cannot run without PyASN1" def setUp(self): self.rsaObj = Crypto.PublicKey.RSA.construct((1L, 2L, 3L, 4L, 5L)) @@ -136,33 +136,33 @@ Test that the _guessStringType method guesses string types correctly. """ - self.assertEquals(keys.Key._guessStringType(keydata.publicRSA_openssh), + self.assertEqual(keys.Key._guessStringType(keydata.publicRSA_openssh), 'public_openssh') - self.assertEquals(keys.Key._guessStringType(keydata.publicDSA_openssh), + self.assertEqual(keys.Key._guessStringType(keydata.publicDSA_openssh), 'public_openssh') - self.assertEquals(keys.Key._guessStringType( + self.assertEqual(keys.Key._guessStringType( keydata.privateRSA_openssh), 'private_openssh') - self.assertEquals(keys.Key._guessStringType( + self.assertEqual(keys.Key._guessStringType( keydata.privateDSA_openssh), 'private_openssh') - self.assertEquals(keys.Key._guessStringType(keydata.publicRSA_lsh), + self.assertEqual(keys.Key._guessStringType(keydata.publicRSA_lsh), 'public_lsh') - self.assertEquals(keys.Key._guessStringType(keydata.publicDSA_lsh), + self.assertEqual(keys.Key._guessStringType(keydata.publicDSA_lsh), 'public_lsh') - self.assertEquals(keys.Key._guessStringType(keydata.privateRSA_lsh), + self.assertEqual(keys.Key._guessStringType(keydata.privateRSA_lsh), 'private_lsh') - self.assertEquals(keys.Key._guessStringType(keydata.privateDSA_lsh), + self.assertEqual(keys.Key._guessStringType(keydata.privateDSA_lsh), 'private_lsh') - self.assertEquals(keys.Key._guessStringType( + self.assertEqual(keys.Key._guessStringType( keydata.privateRSA_agentv3), 'agentv3') - self.assertEquals(keys.Key._guessStringType( + self.assertEqual(keys.Key._guessStringType( keydata.privateDSA_agentv3), 'agentv3') - self.assertEquals(keys.Key._guessStringType( + self.assertEqual(keys.Key._guessStringType( '\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x01\x01'), 'blob') - self.assertEquals(keys.Key._guessStringType( + self.assertEqual(keys.Key._guessStringType( '\x00\x00\x00\x07ssh-dss\x00\x00\x00\x01\x01'), 'blob') - self.assertEquals(keys.Key._guessStringType('not a key'), + self.assertEqual(keys.Key._guessStringType('not a key'), None) def _testPublicPrivateFromString(self, public, private, type, data): @@ -172,16 +172,16 @@ def _testPublicFromString(self, public, type, data): publicKey = keys.Key.fromString(public) self.assertTrue(publicKey.isPublic()) - self.assertEquals(publicKey.type(), type) + self.assertEqual(publicKey.type(), type) for k, v in publicKey.data().items(): - self.assertEquals(data[k], v) + self.assertEqual(data[k], v) def _testPrivateFromString(self, private, type, data): privateKey = keys.Key.fromString(private) self.assertFalse(privateKey.isPublic()) - self.assertEquals(privateKey.type(), type) + self.assertEqual(privateKey.type(), type) for k, v in data.items(): - self.assertEquals(privateKey.data()[k], v) + self.assertEqual(privateKey.data()[k], v) def test_fromOpenSSH(self): """ @@ -189,11 +189,11 @@ """ self._testPublicPrivateFromString(keydata.publicRSA_openssh, keydata.privateRSA_openssh, 'RSA', keydata.RSAData) - self.assertEquals(keys.Key.fromString( + self.assertEqual(keys.Key.fromString( keydata.privateRSA_openssh_encrypted, passphrase='encrypted'), keys.Key.fromString(keydata.privateRSA_openssh)) - self.assertEquals(keys.Key.fromString( + self.assertEqual(keys.Key.fromString( keydata.privateRSA_openssh_alternate), keys.Key.fromString(keydata.privateRSA_openssh)) self._testPublicPrivateFromString(keydata.publicDSA_openssh, @@ -217,7 +217,7 @@ /ow0IqSj0VF72VJN9uSoPpFd4lLT0zN8v42RWja0M8ohWNf+YNJluPgCFE0PT4Vm SUrCyZXsNh6VXwjs3gKQ -----END DSA PRIVATE KEY-----""" - self.assertEquals(keys.Key.fromString(privateDSAData), + self.assertEqual(keys.Key.fromString(privateDSAData), keys.Key.fromString(privateDSAData + '\n')) def test_fromLSH(self): @@ -268,7 +268,7 @@ """ Test that fromFile works correctly. """ - self.assertEquals(keys.Key.fromFile(self.keyFile), + self.assertEqual(keys.Key.fromFile(self.keyFile), keys.Key.fromString(keydata.privateRSA_lsh)) self.assertRaises(keys.BadKeyError, keys.Key.fromFile, self.keyFile, 'bad_type') @@ -281,7 +281,7 @@ """ obj = Crypto.PublicKey.RSA.construct((1L, 2L)) key = keys.Key(obj) - self.assertEquals(key.keyObject, obj) + self.assertEqual(key.keyObject, obj) def test_equal(self): """ @@ -315,10 +315,10 @@ """ Test that the type method returns the correct type for an object. """ - self.assertEquals(keys.Key(self.rsaObj).type(), 'RSA') - self.assertEquals(keys.Key(self.rsaObj).sshType(), 'ssh-rsa') - self.assertEquals(keys.Key(self.dsaObj).type(), 'DSA') - self.assertEquals(keys.Key(self.dsaObj).sshType(), 'ssh-dss') + self.assertEqual(keys.Key(self.rsaObj).type(), 'RSA') + self.assertEqual(keys.Key(self.rsaObj).sshType(), 'ssh-rsa') + self.assertEqual(keys.Key(self.dsaObj).type(), 'DSA') + self.assertEqual(keys.Key(self.dsaObj).sshType(), 'ssh-dss') self.assertRaises(RuntimeError, keys.Key(None).type) self.assertRaises(RuntimeError, keys.Key(None).sshType) self.assertRaises(RuntimeError, keys.Key(self).type) @@ -335,9 +335,9 @@ dsaKey = keys.Key.fromString(dsaBlob) badBlob = common.NS('ssh-bad') self.assertTrue(rsaKey.isPublic()) - self.assertEquals(rsaKey.data(), {'e':2L, 'n':3L}) + self.assertEqual(rsaKey.data(), {'e':2L, 'n':3L}) self.assertTrue(dsaKey.isPublic()) - self.assertEquals(dsaKey.data(), {'p':2L, 'q':3L, 'g':4L, 'y':5L}) + self.assertEqual(dsaKey.data(), {'p':2L, 'q':3L, 'g':4L, 'y':5L}) self.assertRaises(keys.BadKeyError, keys.Key.fromString, badBlob) @@ -366,10 +366,10 @@ """ Test that the Key object generates blobs correctly. """ - self.assertEquals(keys.Key(self.rsaObj).blob(), + self.assertEqual(keys.Key(self.rsaObj).blob(), '\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x01\x02' '\x00\x00\x00\x01\x01') - self.assertEquals(keys.Key(self.dsaObj).blob(), + self.assertEqual(keys.Key(self.dsaObj).blob(), '\x00\x00\x00\x07ssh-dss\x00\x00\x00\x01\x03' '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x02' '\x00\x00\x00\x01\x01') @@ -383,12 +383,12 @@ L{Key.privateBlob} returns the SSH protocol-level format of the private key and raises L{RuntimeError} if the underlying key object is invalid. """ - self.assertEquals(keys.Key(self.rsaObj).privateBlob(), + self.assertEqual(keys.Key(self.rsaObj).privateBlob(), '\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x01\x01' '\x00\x00\x00\x01\x02\x00\x00\x00\x01\x03\x00' '\x00\x00\x01\x04\x00\x00\x00\x01\x04\x00\x00' '\x00\x01\x05') - self.assertEquals(keys.Key(self.dsaObj).privateBlob(), + self.assertEqual(keys.Key(self.dsaObj).privateBlob(), '\x00\x00\x00\x07ssh-dss\x00\x00\x00\x01\x03' '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x02\x00' '\x00\x00\x01\x01\x00\x00\x00\x01\x05') @@ -402,18 +402,18 @@ Test that the Key object generates OpenSSH keys correctly. """ key = keys.Key.fromString(keydata.privateRSA_lsh) - self.assertEquals(key.toString('openssh'), keydata.privateRSA_openssh) - self.assertEquals(key.toString('openssh', 'encrypted'), + self.assertEqual(key.toString('openssh'), keydata.privateRSA_openssh) + self.assertEqual(key.toString('openssh', 'encrypted'), keydata.privateRSA_openssh_encrypted) - self.assertEquals(key.public().toString('openssh'), + self.assertEqual(key.public().toString('openssh'), keydata.publicRSA_openssh[:-8]) # no comment - self.assertEquals(key.public().toString('openssh', 'comment'), + self.assertEqual(key.public().toString('openssh', 'comment'), keydata.publicRSA_openssh) key = keys.Key.fromString(keydata.privateDSA_lsh) - self.assertEquals(key.toString('openssh'), keydata.privateDSA_openssh) - self.assertEquals(key.public().toString('openssh', 'comment'), + self.assertEqual(key.toString('openssh'), keydata.privateDSA_openssh) + self.assertEqual(key.public().toString('openssh', 'comment'), keydata.publicDSA_openssh) - self.assertEquals(key.public().toString('openssh'), + self.assertEqual(key.public().toString('openssh'), keydata.publicDSA_openssh[:-8]) # no comment def test_toLSH(self): @@ -421,12 +421,12 @@ Test that the Key object generates LSH keys correctly. """ key = keys.Key.fromString(keydata.privateRSA_openssh) - self.assertEquals(key.toString('lsh'), keydata.privateRSA_lsh) - self.assertEquals(key.public().toString('lsh'), + self.assertEqual(key.toString('lsh'), keydata.privateRSA_lsh) + self.assertEqual(key.public().toString('lsh'), keydata.publicRSA_lsh) key = keys.Key.fromString(keydata.privateDSA_openssh) - self.assertEquals(key.toString('lsh'), keydata.privateDSA_lsh) - self.assertEquals(key.public().toString('lsh'), + self.assertEqual(key.toString('lsh'), keydata.privateDSA_lsh) + self.assertEqual(key.public().toString('lsh'), keydata.publicDSA_lsh) def test_toAgentv3(self): @@ -434,9 +434,9 @@ Test that the Key object generates Agent v3 keys correctly. """ key = keys.Key.fromString(keydata.privateRSA_openssh) - self.assertEquals(key.toString('agentv3'), keydata.privateRSA_agentv3) + self.assertEqual(key.toString('agentv3'), keydata.privateRSA_agentv3) key = keys.Key.fromString(keydata.privateDSA_openssh) - self.assertEquals(key.toString('agentv3'), keydata.privateDSA_agentv3) + self.assertEqual(key.toString('agentv3'), keydata.privateDSA_agentv3) def test_toStringErrors(self): """ @@ -450,9 +450,9 @@ Test that the Key object generates correct signatures. """ key = keys.Key.fromString(keydata.privateRSA_openssh) - self.assertEquals(key.sign(''), self.rsaSignature) + self.assertEqual(key.sign(''), self.rsaSignature) key = keys.Key.fromString(keydata.privateDSA_openssh) - self.assertEquals(key.sign(''), self.dsaSignature) + self.assertEqual(key.sign(''), self.dsaSignature) def test_verify(self): @@ -472,7 +472,7 @@ """ Test the pretty representation of Key. """ - self.assertEquals(repr(keys.Key(self.rsaObj)), + self.assertEqual(repr(keys.Key(self.rsaObj)), """>> print "hello"']) + return d.addCallback(cb) + + + def test_controlE(self): + """ + CTRL-E can be used as END - setting cursor to end of current + line buffer. + """ + self._testwrite('rint "hello' + '\x01' + 'p' + '\x05' + '"') + d = self.recvlineClient.expect('print "hello"') + def cb(ignore): + self._assertBuffer(['>>> print "hello"']) + return d.addCallback(cb) + + def testDeferred(self): self._testwrite( "from twisted.internet import defer, reactor\n" diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_mixin.py twisted-conch-12.1.0/twisted/conch/test/test_mixin.py --- twisted-conch-10.2.0/twisted/conch/test/test_mixin.py 2006-10-28 01:11:31.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_mixin.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,5 +1,5 @@ # -*- twisted.conch.test.test_mixin -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. import time @@ -40,8 +40,8 @@ for s in L: n = p.rescheduled p.write(s) - self.assertEquals(p.rescheduled, n + 1) - self.assertEquals(t.value(), '') + self.assertEqual(p.rescheduled, n + 1) + self.assertEqual(t.value(), '') p.flush() - self.assertEquals(t.value(), 'foo' + ''.join(L)) + self.assertEqual(t.value(), 'foo' + ''.join(L)) diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_openssh_compat.py twisted-conch-12.1.0/twisted/conch/test/test_openssh_compat.py --- twisted-conch-10.2.0/twisted/conch/test/test_openssh_compat.py 2009-07-02 12:42:42.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_openssh_compat.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -61,7 +61,7 @@ in the data directory """ keys = self.factory.getPublicKeys() - self.assertEquals(len(keys), 1) + self.assertEqual(len(keys), 1) keyTypes = keys.keys() self.assertEqual(keyTypes, ['ssh-rsa']) @@ -72,11 +72,11 @@ keys in the data directory. """ keys = self.factory.getPrivateKeys() - self.assertEquals(len(keys), 2) + self.assertEqual(len(keys), 2) keyTypes = keys.keys() self.assertEqual(set(keyTypes), set(['ssh-rsa', 'ssh-dss'])) - self.assertEquals(self.mockos.seteuidCalls, []) - self.assertEquals(self.mockos.setegidCalls, []) + self.assertEqual(self.mockos.seteuidCalls, []) + self.assertEqual(self.mockos.setegidCalls, []) def test_getPrivateKeysAsRoot(self): @@ -95,8 +95,8 @@ return savedSeteuid(euid) self.patch(os, "seteuid", seteuid) keys = self.factory.getPrivateKeys() - self.assertEquals(len(keys), 2) + self.assertEqual(len(keys), 2) keyTypes = keys.keys() self.assertEqual(set(keyTypes), set(['ssh-rsa', 'ssh-dss'])) - self.assertEquals(self.mockos.seteuidCalls, [0, os.geteuid()]) - self.assertEquals(self.mockos.setegidCalls, [0, os.getegid()]) + self.assertEqual(self.mockos.seteuidCalls, [0, os.geteuid()]) + self.assertEqual(self.mockos.setegidCalls, [0, os.getegid()]) diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_recvline.py twisted-conch-12.1.0/twisted/conch/test/test_recvline.py --- twisted-conch-10.2.0/twisted/conch/test/test_recvline.py 2010-01-19 09:04:17.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_recvline.py 2011-09-12 00:06:03.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_recvline -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -28,181 +28,224 @@ self.pt.makeConnection(self.underlyingTransport) # self.p.makeConnection(self.pt) - def testPrintableCharacters(self): + def test_printableCharacters(self): + """ + When L{HistoricRecvLine} receives a printable character, + it adds it to the current line buffer. + """ self.p.keystrokeReceived('x', None) self.p.keystrokeReceived('y', None) self.p.keystrokeReceived('z', None) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xyz', '')) - def testHorizontalArrows(self): + def test_horizontalArrows(self): + """ + When L{HistoricRecvLine} receives an LEFT_ARROW or + RIGHT_ARROW keystroke it moves the cursor left or right + in the current line buffer, respectively. + """ kR = lambda ch: self.p.keystrokeReceived(ch, None) for ch in 'xyz': kR(ch) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xyz', '')) kR(self.pt.RIGHT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xyz', '')) kR(self.pt.LEFT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('xy', 'z')) + self.assertEqual(self.p.currentLineBuffer(), ('xy', 'z')) kR(self.pt.LEFT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('x', 'yz')) + self.assertEqual(self.p.currentLineBuffer(), ('x', 'yz')) kR(self.pt.LEFT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('', 'xyz')) + self.assertEqual(self.p.currentLineBuffer(), ('', 'xyz')) kR(self.pt.LEFT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('', 'xyz')) + self.assertEqual(self.p.currentLineBuffer(), ('', 'xyz')) kR(self.pt.RIGHT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('x', 'yz')) + self.assertEqual(self.p.currentLineBuffer(), ('x', 'yz')) kR(self.pt.RIGHT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('xy', 'z')) + self.assertEqual(self.p.currentLineBuffer(), ('xy', 'z')) kR(self.pt.RIGHT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xyz', '')) kR(self.pt.RIGHT_ARROW) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xyz', '')) - def testNewline(self): + def test_newline(self): + """ + When {HistoricRecvLine} receives a newline, it adds the current + line buffer to the end of its history buffer. + """ kR = lambda ch: self.p.keystrokeReceived(ch, None) for ch in 'xyz\nabc\n123\n': kR(ch) - self.assertEquals(self.p.currentHistoryBuffer(), + self.assertEqual(self.p.currentHistoryBuffer(), (('xyz', 'abc', '123'), ())) kR('c') kR('b') kR('a') - self.assertEquals(self.p.currentHistoryBuffer(), + self.assertEqual(self.p.currentHistoryBuffer(), (('xyz', 'abc', '123'), ())) kR('\n') - self.assertEquals(self.p.currentHistoryBuffer(), + self.assertEqual(self.p.currentHistoryBuffer(), (('xyz', 'abc', '123', 'cba'), ())) - def testVerticalArrows(self): + def test_verticalArrows(self): + """ + When L{HistoricRecvLine} receives UP_ARROW or DOWN_ARROW + keystrokes it move the current index in the current history + buffer up or down, and resets the current line buffer to the + previous or next line in history, respectively for each. + """ kR = lambda ch: self.p.keystrokeReceived(ch, None) for ch in 'xyz\nabc\n123\n': kR(ch) - self.assertEquals(self.p.currentHistoryBuffer(), + self.assertEqual(self.p.currentHistoryBuffer(), (('xyz', 'abc', '123'), ())) - self.assertEquals(self.p.currentLineBuffer(), ('', '')) + self.assertEqual(self.p.currentLineBuffer(), ('', '')) kR(self.pt.UP_ARROW) - self.assertEquals(self.p.currentHistoryBuffer(), + self.assertEqual(self.p.currentHistoryBuffer(), (('xyz', 'abc'), ('123',))) - self.assertEquals(self.p.currentLineBuffer(), ('123', '')) + self.assertEqual(self.p.currentLineBuffer(), ('123', '')) kR(self.pt.UP_ARROW) - self.assertEquals(self.p.currentHistoryBuffer(), + self.assertEqual(self.p.currentHistoryBuffer(), (('xyz',), ('abc', '123'))) - self.assertEquals(self.p.currentLineBuffer(), ('abc', '')) + self.assertEqual(self.p.currentLineBuffer(), ('abc', '')) kR(self.pt.UP_ARROW) - self.assertEquals(self.p.currentHistoryBuffer(), + self.assertEqual(self.p.currentHistoryBuffer(), ((), ('xyz', 'abc', '123'))) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xyz', '')) kR(self.pt.UP_ARROW) - self.assertEquals(self.p.currentHistoryBuffer(), + self.assertEqual(self.p.currentHistoryBuffer(), ((), ('xyz', 'abc', '123'))) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xyz', '')) for i in range(4): kR(self.pt.DOWN_ARROW) - self.assertEquals(self.p.currentHistoryBuffer(), + self.assertEqual(self.p.currentHistoryBuffer(), (('xyz', 'abc', '123'), ())) - def testHome(self): + def test_home(self): + """ + When L{HistoricRecvLine} receives a HOME keystroke it moves the + cursor to the beginning of the current line buffer. + """ kR = lambda ch: self.p.keystrokeReceived(ch, None) for ch in 'hello, world': kR(ch) - self.assertEquals(self.p.currentLineBuffer(), ('hello, world', '')) + self.assertEqual(self.p.currentLineBuffer(), ('hello, world', '')) kR(self.pt.HOME) - self.assertEquals(self.p.currentLineBuffer(), ('', 'hello, world')) + self.assertEqual(self.p.currentLineBuffer(), ('', 'hello, world')) - def testEnd(self): + def test_end(self): + """ + When L{HistoricRecvLine} receives a END keystroke it moves the cursor + to the end of the current line buffer. + """ kR = lambda ch: self.p.keystrokeReceived(ch, None) for ch in 'hello, world': kR(ch) - self.assertEquals(self.p.currentLineBuffer(), ('hello, world', '')) + self.assertEqual(self.p.currentLineBuffer(), ('hello, world', '')) kR(self.pt.HOME) kR(self.pt.END) - self.assertEquals(self.p.currentLineBuffer(), ('hello, world', '')) + self.assertEqual(self.p.currentLineBuffer(), ('hello, world', '')) - def testBackspace(self): + def test_backspace(self): + """ + When L{HistoricRecvLine} receives a BACKSPACE keystroke it deletes + the character immediately before the cursor. + """ kR = lambda ch: self.p.keystrokeReceived(ch, None) for ch in 'xyz': kR(ch) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xyz', '')) kR(self.pt.BACKSPACE) - self.assertEquals(self.p.currentLineBuffer(), ('xy', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xy', '')) kR(self.pt.LEFT_ARROW) kR(self.pt.BACKSPACE) - self.assertEquals(self.p.currentLineBuffer(), ('', 'y')) + self.assertEqual(self.p.currentLineBuffer(), ('', 'y')) kR(self.pt.BACKSPACE) - self.assertEquals(self.p.currentLineBuffer(), ('', 'y')) + self.assertEqual(self.p.currentLineBuffer(), ('', 'y')) - def testDelete(self): + def test_delete(self): + """ + When L{HistoricRecvLine} receives a DELETE keystroke, it + delets the character immediately after the cursor. + """ kR = lambda ch: self.p.keystrokeReceived(ch, None) for ch in 'xyz': kR(ch) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xyz', '')) kR(self.pt.DELETE) - self.assertEquals(self.p.currentLineBuffer(), ('xyz', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xyz', '')) kR(self.pt.LEFT_ARROW) kR(self.pt.DELETE) - self.assertEquals(self.p.currentLineBuffer(), ('xy', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xy', '')) kR(self.pt.LEFT_ARROW) kR(self.pt.DELETE) - self.assertEquals(self.p.currentLineBuffer(), ('x', '')) + self.assertEqual(self.p.currentLineBuffer(), ('x', '')) kR(self.pt.LEFT_ARROW) kR(self.pt.DELETE) - self.assertEquals(self.p.currentLineBuffer(), ('', '')) + self.assertEqual(self.p.currentLineBuffer(), ('', '')) kR(self.pt.DELETE) - self.assertEquals(self.p.currentLineBuffer(), ('', '')) + self.assertEqual(self.p.currentLineBuffer(), ('', '')) - def testInsert(self): + def test_insert(self): + """ + When not in INSERT mode, L{HistoricRecvLine} inserts the typed + character at the cursor before the next character. + """ kR = lambda ch: self.p.keystrokeReceived(ch, None) for ch in 'xyz': kR(ch) - # kR(self.pt.INSERT) - kR(self.pt.LEFT_ARROW) kR('A') - self.assertEquals(self.p.currentLineBuffer(), ('xyA', 'z')) + self.assertEqual(self.p.currentLineBuffer(), ('xyA', 'z')) kR(self.pt.LEFT_ARROW) kR('B') - self.assertEquals(self.p.currentLineBuffer(), ('xyB', 'Az')) + self.assertEqual(self.p.currentLineBuffer(), ('xyB', 'Az')) - def testTypeover(self): + def test_typeover(self): + """ + When in INSERT mode and upon receiving a keystroke with a printable + character, L{HistoricRecvLine} replaces the character at + the cursor with the typed character rather than inserting before. + Ah, the ironies of INSERT mode. + """ kR = lambda ch: self.p.keystrokeReceived(ch, None) for ch in 'xyz': @@ -212,11 +255,25 @@ kR(self.pt.LEFT_ARROW) kR('A') - self.assertEquals(self.p.currentLineBuffer(), ('xyA', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xyA', '')) kR(self.pt.LEFT_ARROW) kR('B') - self.assertEquals(self.p.currentLineBuffer(), ('xyB', '')) + self.assertEqual(self.p.currentLineBuffer(), ('xyB', '')) + + + def test_unprintableCharacters(self): + """ + When L{HistoricRecvLine} receives a keystroke for an unprintable + function key with no assigned behavior, the line buffer is unmodified. + """ + kR = lambda ch: self.p.keystrokeReceived(ch, None) + pt = self.pt + + for ch in (pt.F1, pt.F2, pt.F3, pt.F4, pt.F5, pt.F6, pt.F7, pt.F8, + pt.F9, pt.F10, pt.F11, pt.F12, pt.PGUP, pt.PGDN): + kR(ch) + self.assertEqual(self.p.currentLineBuffer(), ('', '')) from twisted.conch import telnet @@ -375,9 +432,9 @@ def _assertBuffer(self, lines): receivedLines = str(self.recvlineClient).splitlines() expectedLines = lines + ([''] * (self.HEIGHT - len(lines) - 1)) - self.assertEquals(len(receivedLines), len(expectedLines)) + self.assertEqual(len(receivedLines), len(expectedLines)) for i in range(len(receivedLines)): - self.assertEquals( + self.assertEqual( receivedLines[i], expectedLines[i], str(receivedLines[max(0, i-1):i+1]) + " != " + @@ -531,8 +588,8 @@ pass def trap(failure): failure.trap(error.ProcessTerminated) - self.assertEquals(failure.value.exitCode, None) - self.assertEquals(failure.value.status, 9) + self.assertEqual(failure.value.exitCode, None) + self.assertEqual(failure.value.status, 9) return self.testTerminal.onDisconnection.addErrback(trap) def _testwrite(self, bytes): diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_scripts.py twisted-conch-12.1.0/twisted/conch/test/test_scripts.py --- twisted-conch-10.2.0/twisted/conch/test/test_scripts.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_scripts.py 2012-01-15 02:23:55.000000000 +0000 @@ -0,0 +1,82 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Tests for the command-line interfaces to conch. +""" + +try: + import pyasn1 +except ImportError: + pyasn1Skip = "Cannot run without PyASN1" +else: + pyasn1Skip = None + +try: + import Crypto +except ImportError: + cryptoSkip = "can't run w/o PyCrypto" +else: + cryptoSkip = None + +try: + import tty +except ImportError: + ttySkip = "can't run w/o tty" +else: + ttySkip = None + +try: + import Tkinter +except ImportError: + tkskip = "can't run w/o Tkinter" +else: + try: + Tkinter.Tk().destroy() + except Tkinter.TclError, e: + tkskip = "Can't test Tkinter: " + str(e) + else: + tkskip = None + +from twisted.trial.unittest import TestCase +from twisted.scripts.test.test_scripts import ScriptTestsMixin +from twisted.python.test.test_shellcomp import ZshScriptTestMixin + + + +class ScriptTests(TestCase, ScriptTestsMixin): + """ + Tests for the Conch scripts. + """ + skip = pyasn1Skip or cryptoSkip + + + def test_conch(self): + self.scriptTest("conch/conch") + test_conch.skip = ttySkip or skip + + + def test_cftp(self): + self.scriptTest("conch/cftp") + test_cftp.skip = ttySkip or skip + + + def test_ckeygen(self): + self.scriptTest("conch/ckeygen") + + + def test_tkconch(self): + self.scriptTest("conch/tkconch") + test_tkconch.skip = tkskip or skip + + + +class ZshIntegrationTestCase(TestCase, ZshScriptTestMixin): + """ + Test that zsh completion functions are generated without error + """ + generateFor = [('conch', 'twisted.conch.scripts.conch.ClientOptions'), + ('cftp', 'twisted.conch.scripts.cftp.ClientOptions'), + ('ckeygen', 'twisted.conch.scripts.ckeygen.GeneralOptions'), + ('tkconch', 'twisted.conch.scripts.tkconch.GeneralOptions'), + ] diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_session.py twisted-conch-12.1.0/twisted/conch/test/test_session.py --- twisted-conch-10.2.0/twisted/conch/test/test_session.py 2010-03-31 18:58:26.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_session.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2007-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -11,6 +11,7 @@ from zope.interface import implements +from twisted.internet.address import IPv4Address from twisted.internet.error import ProcessTerminated, ProcessDone from twisted.python.failure import Failure from twisted.conch.ssh import common, session, connection @@ -361,7 +362,7 @@ """ - def __init__(self): + def __init__(self, transport=None): """ Initialize our instance variables. """ @@ -370,6 +371,7 @@ self.requests = {} self.eofs = {} self.closes = {} + self.transport = transport def logPrefix(self): @@ -418,9 +420,6 @@ - - - class StubTransport: """ A stub transport which records the data written. @@ -436,6 +435,20 @@ close = False + def getPeer(self): + """ + Return an arbitrary L{IAddress}. + """ + return IPv4Address('TCP', 'remotehost', 8888) + + + def getHost(self): + """ + Return an arbitrary L{IAddress}. + """ + return IPv4Address('TCP', 'localhost', 9999) + + def write(self, data): """ Record data in the buffer. @@ -519,7 +532,7 @@ """ s = session.SSHSession(avatar=object) # use object because it doesn't # have an adapter - self.assertEquals(s.buf, '') + self.assertEqual(s.buf, '') self.assertIdentical(s.client, None) self.assertIdentical(s.session, None) @@ -532,7 +545,7 @@ self.session.dataReceived('1') self.session.client = StubClient() self.session.dataReceived('2') - self.assertEquals(self.session.client.transport.buf, '2') + self.assertEqual(self.session.client.transport.buf, '2') def test_client_extReceived(self): """ @@ -544,7 +557,7 @@ self.session.extReceived(255, '2') # 255 is arbitrary self.session.client = StubClient() self.session.extReceived(connection.EXTENDED_DATA_STDERR, '3') - self.assertEquals(self.session.client.transport.err, '3') + self.assertEqual(self.session.client.transport.err, '3') def test_client_extReceivedWithoutWriteErr(self): @@ -632,10 +645,10 @@ self.session.requestReceived('subsystem', common.NS('TestSubsystem') + 'data') - self.assertEquals(self.session.conn.data[self.session], + self.assertEqual(self.session.conn.data[self.session], ['\x00\x00\x00\x0dTestSubsystemdata~']) self.session.dataReceived('more data') - self.assertEquals(self.session.conn.data[self.session][-1], + self.assertEqual(self.session.conn.data[self.session][-1], 'more data~') @@ -657,7 +670,7 @@ RuntimeError). """ errors = self.flushLoggedErrors(RuntimeError) - self.assertEquals(len(errors), 1, "Multiple RuntimeErrors raised: %s" % + self.assertEqual(len(errors), 1, "Multiple RuntimeErrors raised: %s" % '\n'.join([repr(error) for error in errors])) errors[0].trap(RuntimeError) @@ -690,12 +703,12 @@ self.assertTrue(ret) self.assertSessionIsStubSession() self.session.dataReceived('some data\x00') - self.assertEquals(self.session.session.shellTransport.data, + self.assertEqual(self.session.session.shellTransport.data, 'some data\x00') - self.assertEquals(self.session.conn.data[self.session], + self.assertEqual(self.session.conn.data[self.session], ['some data\x00', '\r\n']) self.assertTrue(self.session.session.shellTransport.closed) - self.assertEquals(self.session.conn.requests[self.session], + self.assertEqual(self.session.conn.requests[self.session], [('exit-status', '\x00\x00\x00\x00', False)]) @@ -719,7 +732,7 @@ session.SSHSessionProcessProtocol) self.assertIdentical(self.session.session.execProtocol, self.session.client) - self.assertEquals(self.session.session.execCommandLine, + self.assertEqual(self.session.session.execCommandLine, 'success') @@ -733,14 +746,14 @@ self.assertTrue(ret) self.assertSessionIsStubSession() self.session.dataReceived('some data') - self.assertEquals(self.session.session.execTransport.data, 'some data') - self.assertEquals(self.session.conn.data[self.session], + self.assertEqual(self.session.session.execTransport.data, 'some data') + self.assertEqual(self.session.conn.data[self.session], ['hello', 'some data', '\r\n']) self.session.eofReceived() self.session.closeReceived() self.session.closed() self.assertTrue(self.session.session.execTransport.closed) - self.assertEquals(self.session.conn.requests[self.session], + self.assertEqual(self.session.conn.requests[self.session], [('exit-status', '\x00\x00\x00\x00', False)]) @@ -761,7 +774,7 @@ # 'good' terminal type succeeds self.assertTrue(self.session.requestReceived('pty_req', session.packRequest_pty_req('good', (1, 2, 3, 4), ''))) - self.assertEquals(self.session.session.ptyRequest, + self.assertEqual(self.session.session.ptyRequest, ('good', (1, 2, 3, 4), [])) @@ -779,7 +792,7 @@ self.assertSessionIsStubSession() self.assertTrue(self.session.requestReceived('window_change', session.packRequest_window_change((1, 2, 3, 4)))) - self.assertEquals(self.session.session.windowChange, + self.assertEqual(self.session.session.windowChange, (1, 2, 3, 4)) @@ -895,11 +908,11 @@ protocol.connectionMade() wrapped = session.wrapProtocol(protocol) wrapped.dataReceived('dataReceived') - self.assertEquals(protocol.transport.buf, 'dataReceived') + self.assertEqual(protocol.transport.buf, 'dataReceived') wrapped.write('data') wrapped.writeSequence(['1', '2']) wrapped.loseConnection() - self.assertEquals(protocol.data, 'data12') + self.assertEqual(protocol.data, 'data12') protocol.reason.trap(error.ConnectionDone) def test_wrapProcessProtocol_Protocol(self): @@ -914,7 +927,7 @@ process_protocol = session.wrapProcessProtocol(protocol) process_protocol.connectionMade() process_protocol.outReceived('data') - self.assertEquals(protocol.transport.buf, 'data~') + self.assertEqual(protocol.transport.buf, 'data~') process_protocol.processEnded(failure.Failure( error.ProcessTerminated(0, None, None))) protocol.reason.trap(error.ProcessTerminated) @@ -941,7 +954,7 @@ byte mode number uint32 mode value """ - self.assertEquals(session.parseRequest_pty_req(common.NS('xterm') + + self.assertEqual(session.parseRequest_pty_req(common.NS('xterm') + struct.pack('>4L', 1, 2, 3, 4) + common.NS( @@ -956,7 +969,7 @@ packed = session.packRequest_pty_req('xterm', (2, 1, 3, 4), '\x05\x00\x00\x00\x06') - self.assertEquals(packed, + self.assertEqual(packed, common.NS('xterm') + struct.pack('>4L', 1, 2, 3, 4) + common.NS(struct.pack('>BL', 5, 6))) @@ -967,7 +980,7 @@ """ packed = session.packRequest_pty_req('xterm', (2, 1, 3, 4), '\x05\x00\x00\x00\x06') - self.assertEquals(packed, + self.assertEqual(packed, common.NS('xterm') + struct.pack('>4L', 1, 2, 3, 4) + common.NS(struct.pack('>BL', 5, 6))) @@ -983,7 +996,7 @@ parseRequest_window_change() returns (rows, columns, x pixels, y pixels). """ - self.assertEquals(session.parseRequest_window_change( + self.assertEqual(session.parseRequest_window_change( struct.pack('>4L', 1, 2, 3, 4)), (2, 1, 3, 4)) @@ -991,7 +1004,7 @@ """ See test_parseRequest_window_change for the payload format. """ - self.assertEquals(session.packRequest_window_change((2, 1, 3, 4)), + self.assertEqual(session.packRequest_window_change((2, 1, 3, 4)), struct.pack('>4L', 1, 2, 3, 4)) @@ -1002,9 +1015,10 @@ """ def setUp(self): - self.session = session.SSHSession( - conn=StubConnection(), remoteWindow=500, remoteMaxPacket=100) self.transport = StubTransport() + self.session = session.SSHSession( + conn=StubConnection(self.transport), remoteWindow=500, + remoteMaxPacket=100) self.pp = session.SSHSessionProcessProtocol(self.session) self.pp.makeConnection(self.transport) @@ -1030,7 +1044,25 @@ SSHSessionProcessProtocol should set self.session to the session passed to the __init__ method. """ - self.assertEquals(self.pp.session, self.session) + self.assertEqual(self.pp.session, self.session) + + + def test_getHost(self): + """ + SSHSessionProcessProtocol.getHost() just delegates to its + session.conn.transport.getHost(). + """ + self.assertEqual( + self.session.conn.transport.getHost(), self.pp.getHost()) + + + def test_getPeer(self): + """ + SSHSessionProcessProtocol.getPeer() just delegates to its + session.conn.transport.getPeer(). + """ + self.assertEqual( + self.session.conn.transport.getPeer(), self.pp.getPeer()) def test_connectionMade(self): @@ -1040,7 +1072,7 @@ """ self.session.buf = 'buffer' self.pp.connectionMade() - self.assertEquals(self.transport.buf, 'buffer') + self.assertEqual(self.transport.buf, 'buffer') def test_getSignalName(self): @@ -1052,7 +1084,7 @@ signalName = 'SIG' + signalName signalValue = getattr(signal, signalName) sshName = self.pp._getSignalName(signalValue) - self.assertEquals(sshName, signalName, + self.assertEqual(sshName, signalName, "%i: %s != %s" % (signalValue, sshName, signalName)) @@ -1065,7 +1097,7 @@ signal.SIGTwistedTest = signal.NSIG + 1 # value can't exist normally # Force reinitialization of signals self.pp._signalValuesToNames = None - self.assertEquals(self.pp._getSignalName(signal.SIGTwistedTest), + self.assertEqual(self.pp._getSignalName(signal.SIGTwistedTest), 'SIGTwistedTest@' + sys.platform) @@ -1080,7 +1112,7 @@ the session's write method. """ self.pp.outReceived('test data') - self.assertEquals(self.session.conn.data[self.session], + self.assertEqual(self.session.conn.data[self.session], ['test data']) @@ -1090,7 +1122,7 @@ session channel's write method. """ self.pp.write('test data') - self.assertEquals(self.session.conn.data[self.session], + self.assertEqual(self.session.conn.data[self.session], ['test data']) def test_writeSequence(self): @@ -1099,7 +1131,7 @@ joined together and sent to the session channel's write method. """ self.pp.writeSequence(['test ', 'data']) - self.assertEquals(self.session.conn.data[self.session], + self.assertEqual(self.session.conn.data[self.session], ['test data']) @@ -1109,7 +1141,7 @@ the session's writeExtended method. """ self.pp.errReceived('test data') - self.assertEquals(self.session.conn.extData[self.session], + self.assertEqual(self.session.conn.extData[self.session], [(1, 'test data')]) @@ -1221,4 +1253,4 @@ client = session.SSHSessionClient() client.transport = StubTransport() client.dataReceived('test data') - self.assertEquals(client.transport.buf, 'test data') + self.assertEqual(client.transport.buf, 'test data') diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_ssh.py twisted-conch-12.1.0/twisted/conch/test/test_ssh.py --- twisted-conch-10.2.0/twisted/conch/test/test_ssh.py 2010-06-26 18:40:59.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_ssh.py 2012-01-15 02:23:55.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -22,6 +22,7 @@ from twisted.conch.test.keydata import publicRSA_openssh, privateRSA_openssh from twisted.conch.test.keydata import publicDSA_openssh, privateDSA_openssh from twisted.cred import portal +from twisted.cred.error import UnauthorizedLogin from twisted.internet import defer, protocol, reactor from twisted.internet.error import ProcessTerminated from twisted.python import failure, log @@ -31,46 +32,81 @@ -class ConchTestRealm: +class ConchTestRealm(object): + """ + A realm which expects a particular avatarId to log in once and creates a + L{ConchTestAvatar} for that request. + + @ivar expectedAvatarID: The only avatarID that this realm will produce an + avatar for. + + @ivar avatar: A reference to the avatar after it is requested. + """ + avatar = None + + def __init__(self, expectedAvatarID): + self.expectedAvatarID = expectedAvatarID + def requestAvatar(self, avatarID, mind, *interfaces): - unittest.assertEquals(avatarID, 'testuser') - a = ConchTestAvatar() - return interfaces[0], a, a.logout + """ + Return a new L{ConchTestAvatar} if the avatarID matches the expected one + and this is the first avatar request. + """ + if avatarID == self.expectedAvatarID: + if self.avatar is not None: + raise UnauthorizedLogin("Only one login allowed") + self.avatar = ConchTestAvatar() + return interfaces[0], self.avatar, self.avatar.logout + raise UnauthorizedLogin( + "Only %r may log in, not %r" % (self.expectedAvatarID, avatarID)) + + class ConchTestAvatar(avatar.ConchUser): + """ + An avatar against which various SSH features can be tested. + + @ivar loggedOut: A flag indicating whether the avatar logout method has been + called. + """ loggedOut = False def __init__(self): avatar.ConchUser.__init__(self) self.listeners = {} + self.globalRequests = {} self.channelLookup.update({'session': session.SSHSession, 'direct-tcpip':forwarding.openConnectForwardingClient}) self.subsystemLookup.update({'crazy': CrazySubsystem}) + def global_foo(self, data): - unittest.assertEquals(data, 'bar') + self.globalRequests['foo'] = data return 1 + def global_foo_2(self, data): - unittest.assertEquals(data, 'bar2') + self.globalRequests['foo_2'] = data return 1, 'data' + def global_tcpip_forward(self, data): host, port = forwarding.unpackGlobal_tcpip_forward(data) - try: listener = reactor.listenTCP(port, - forwarding.SSHListenForwardingFactory(self.conn, - (host, port), + try: + listener = reactor.listenTCP( + port, forwarding.SSHListenForwardingFactory( + self.conn, (host, port), forwarding.SSHListenServerForwardingChannel), - interface = host) + interface=host) except: - log.err() - unittest.fail("something went wrong with remote->local forwarding") + log.err(None, "something went wrong with remote->local forwarding") return 0 else: self.listeners[(host, port)] = listener return 1 + def global_cancel_tcpip_forward(self, data): host, port = forwarding.unpackGlobal_tcpip_forward(data) listener = self.listeners.get((host, port), None) @@ -80,41 +116,49 @@ listener.stopListening() return 1 + def logout(self): self.loggedOut = True for listener in self.listeners.values(): log.msg('stopListening %s' % listener) listener.stopListening() -class ConchSessionForTestAvatar: + +class ConchSessionForTestAvatar(object): + """ + An ISession adapter for ConchTestAvatar. + """ def __init__(self, avatar): - unittest.assert_(isinstance(avatar, ConchTestAvatar)) + """ + Initialize the session and create a reference to it on the avatar for + later inspection. + """ self.avatar = avatar + self.avatar._testSession = self self.cmd = None self.proto = None self.ptyReq = False self.eof = 0 + self.onClose = defer.Deferred() + def getPty(self, term, windowSize, attrs): log.msg('pty req') - unittest.assertEquals(term, 'conch-test-term') - unittest.assertEquals(windowSize, (24, 80, 0, 0)) + self._terminalType = term + self._windowSize = windowSize self.ptyReq = True + def openShell(self, proto): - log.msg('openning shell') - unittest.assertEquals(self.ptyReq, True) + log.msg('opening shell') self.proto = proto EchoTransport(proto) self.cmd = 'shell' + def execCommand(self, proto, cmd): self.cmd = cmd - unittest.assert_(cmd.split()[0] in ['false', 'echo', 'secho', 'eecho','jumboliah'], - 'invalid command: %s' % cmd.split()[0]) - if cmd == 'jumboliah': - raise error.ConchError('bad exec') self.proto = proto f = cmd.split()[0] if f == 'false': @@ -134,26 +178,19 @@ t = ErrEchoTransport(proto) t.write(cmd[6:]) t.loseConnection() + else: + raise error.ConchError('bad exec') self.avatar.conn.transport.expectedLoseConnection = 1 -# def closeReceived(self): -# #if self.proto: -# # self.proto.transport.loseConnection() -# self.loseConnection() def eofReceived(self): self.eof = 1 + def closed(self): log.msg('closed cmd "%s"' % self.cmd) - if self.cmd == 'echo hello': - rwl = self.proto.session.remoteWindowLeft - unittest.assertEquals(rwl, 4) - elif self.cmd == 'eecho hello': - rwl = self.proto.session.remoteWindowLeft - unittest.assertEquals(rwl, 4) - elif self.cmd == 'shell': - unittest.assert_(self.eof) + self.remoteWindowLeftAtClose = self.proto.session.remoteWindowLeft + self.onClose.callback(None) from twisted.python import components components.registerAdapter(ConchSessionForTestAvatar, ConchTestAvatar, session.ISession) @@ -274,34 +311,35 @@ def testCounter(self): c = transport._Counter('\x00\x00', 2) for i in xrange(256 * 256): - self.assertEquals(c(), struct.pack('!H', (i + 1) % (2 ** 16))) + self.assertEqual(c(), struct.pack('!H', (i + 1) % (2 ** 16))) # It should wrap around, too. for i in xrange(256 * 256): - self.assertEquals(c(), struct.pack('!H', (i + 1) % (2 ** 16))) + self.assertEqual(c(), struct.pack('!H', (i + 1) % (2 ** 16))) class ConchTestPublicKeyChecker(checkers.SSHPublicKeyDatabase): def checkKey(self, credentials): - unittest.assertEquals(credentials.username, 'testuser', 'bad username') - unittest.assertEquals(credentials.blob, keys.Key.fromString(publicDSA_openssh).blob()) - return 1 + blob = keys.Key.fromString(publicDSA_openssh).blob() + if credentials.username == 'testuser' and credentials.blob == blob: + return True + return False + class ConchTestPasswordChecker: credentialInterfaces = checkers.IUsernamePassword, def requestAvatarId(self, credentials): - unittest.assertEquals(credentials.username, 'testuser', 'bad username') - unittest.assertEquals(credentials.password, 'testpass', 'bad password') - return defer.succeed(credentials.username) + if credentials.username == 'testuser' and credentials.password == 'testpass': + return defer.succeed(credentials.username) + return defer.fail(Exception("Bad credentials")) + class ConchTestSSHChecker(checkers.SSHProtocolChecker): def areDone(self, avatarId): - unittest.assertEquals(avatarId, 'testuser') - if len(self.successfulCredentials[avatarId]) < 2: - return 0 - else: - return 1 + if avatarId != 'testuser' or len(self.successfulCredentials[avatarId]) < 2: + return False + return True class ConchTestServerFactory(factory.SSHFactory): noisy = 0 @@ -360,10 +398,11 @@ # connection. Other, older versions (for example, # OpenSSH_5.1p1), won't. So accept this particular error here, # but no others. - unittest.assertEquals( - reasonCode, transport.DISCONNECT_BY_APPLICATION, - 'got disconnect for %s: reason %s, desc: %s' % ( - self, reasonCode, desc)) + if reasonCode != transport.DISCONNECT_BY_APPLICATION: + log.err( + Exception( + 'got disconnect for %s: reason %s, desc: %s' % ( + self, reasonCode, desc))) self.loseConnection() def receiveUnimplemented(self, seqID): @@ -377,26 +416,32 @@ ConchTestBase.connectionLost(self, reason) transport.SSHServerTransport.connectionLost(self, reason) + class ConchTestClient(ConchTestBase, transport.SSHClientTransport): """ - @ivar completed: A L{Deferred} which will fire when the expected number - of results have been collected. + @ivar _channelFactory: A callable which accepts an SSH connection and + returns a channel which will be attached to a new channel on that + connection. """ - def __init__(self): - self.completed = defer.Deferred() + def __init__(self, channelFactory): + self._channelFactory = channelFactory def connectionLost(self, reason): ConchTestBase.connectionLost(self, reason) transport.SSHClientTransport.connectionLost(self, reason) def verifyHostKey(self, key, fp): - unittest.assertEquals(key, keys.Key.fromString(publicRSA_openssh).blob()) - unittest.assertEquals(fp,'3d:13:5f:cb:c9:79:8a:93:06:27:65:bc:3d:0b:8f:af') - return defer.succeed(1) + keyMatch = key == keys.Key.fromString(publicRSA_openssh).blob() + fingerprintMatch = ( + fp == '3d:13:5f:cb:c9:79:8a:93:06:27:65:bc:3d:0b:8f:af') + if keyMatch and fingerprintMatch: + return defer.succeed(1) + return defer.fail(Exception("Key or fingerprint mismatch")) def connectionSecure(self): self.requestService(ConchTestClientAuth('testuser', - ConchTestClientConnection(self.completed))) + ConchTestClientConnection(self._channelFactory))) + class ConchTestClientAuth(userauth.SSHUserAuthClient): @@ -420,6 +465,7 @@ def getPublicKey(self): return keys.Key.fromString(publicDSA_openssh) + class ConchTestClientConnection(connection.SSHConnection): """ @ivar _completed: A L{Deferred} which will be fired when the number of @@ -429,349 +475,78 @@ results = 0 totalResults = 8 - def __init__(self, completed): + def __init__(self, channelFactory): connection.SSHConnection.__init__(self) - self._completed = completed - + self._channelFactory = channelFactory def serviceStarted(self): - self.openChannel(SSHTestFailExecChannel(conn = self)) - self.openChannel(SSHTestFalseChannel(conn = self)) - self.openChannel(SSHTestEchoChannel(localWindow=4, localMaxPacket=5, conn = self)) - self.openChannel(SSHTestErrChannel(localWindow=4, localMaxPacket=5, conn = self)) - self.openChannel(SSHTestMaxPacketChannel(localWindow=12, localMaxPacket=1, conn = self)) - self.openChannel(SSHTestShellChannel(conn = self)) - self.openChannel(SSHTestSubsystemChannel(conn = self)) - self.openChannel(SSHUnknownChannel(conn = self)) - - def addResult(self): - self.results += 1 - log.msg('got %s of %s results' % (self.results, self.totalResults)) - if self.results == self.totalResults: - self.transport.expectedLoseConnection = 1 - self.serviceStopped() - self._completed.callback(None) + self.openChannel(self._channelFactory(conn=self)) - class SSHUnknownChannel(channel.SSHChannel): - name = 'crazy-unknown-channel' - - def openFailed(self, reason): - """ - good .... good - """ - log.msg('unknown open failed') - self.conn.addResult() + class SSHTestChannel(channel.SSHChannel): - def channelOpen(self, ignored): - unittest.fail("opened unknown channel") + def __init__(self, name, opened, *args, **kwargs): + self.name = name + self._opened = opened + self.received = [] + self.receivedExt = [] + self.onClose = defer.Deferred() + channel.SSHChannel.__init__(self, *args, **kwargs) - class SSHTestFailExecChannel(channel.SSHChannel): - - name = 'session' - - def openFailed(self, reason): - unittest.fail('fail exec open failed: %s' % reason) - - def channelOpen(self, ignore): - d = self.conn.sendRequest(self, 'exec', common.NS('jumboliah'), 1) - d.addCallback(self._cbRequestWorked) - d.addErrback(self._ebRequestWorked) - log.msg('opened fail exec') - - def _cbRequestWorked(self, ignored): - unittest.fail('fail exec succeeded') - - def _ebRequestWorked(self, ignored): - log.msg('fail exec finished') - self.conn.addResult() - self.loseConnection() - - class SSHTestFalseChannel(channel.SSHChannel): - - name = 'session' def openFailed(self, reason): - unittest.fail('false open failed: %s' % reason) - - def channelOpen(self, ignored): - d = self.conn.sendRequest(self, 'exec', common.NS('false'), 1) - d.addCallback(self._cbRequestWorked) - d.addErrback(self._ebRequestFailed) - log.msg('opened false') - - - def _cbRequestWorked(self, ignored): - """ - The false channel request is expected to succeed. No need to check - for this to be actually called, since it will automatically be - errbacked if this channel is closed with the deferred left pending. - """ - - - def _ebRequestFailed(self, reason): - """ - The request deferred should never errback. - """ - log.err(Exception('False channel request errbacked.')) - - - def dataReceived(self, data): - unittest.fail('got data when using false') - - - def request_exit_status(self, status): - self.status, = struct.unpack('>L', status) - - - def closed(self): - if self.status == 0: - log.err(Exception('false exit status was 0')) - log.msg('finished false') - self.conn.addResult() - return 1 - + self._opened.errback(reason) - class SSHTestEchoChannel(channel.SSHChannel): - - name = 'session' - testBuf = '' - eofCalled = 0 - - def openFailed(self, reason): - unittest.fail('echo open failed: %s' % reason) - def channelOpen(self, ignore): - d = self.conn.sendRequest(self, 'exec', common.NS('echo hello'), 1) - d.addErrback(self._ebRequestFailed) - log.msg('opened echo') + self._opened.callback(self) - def _ebRequestFailed(self, reason): - unittest.fail('echo exec failed: %s' % reason) def dataReceived(self, data): - self.testBuf += data - - def errReceived(self, dataType, data): - unittest.fail('echo channel got extended data') + self.received.append(data) - def request_exit_status(self, status): - self.status ,= struct.unpack('>L', status) - - def eofReceived(self): - log.msg('eof received') - self.eofCalled = 1 - - def closed(self): - if self.status != 0: - unittest.fail('echo exit status was not 0: %i' % self.status) - if self.testBuf != "hello\r\n": - unittest.fail('echo did not return hello: %s' % repr(self.testBuf)) - unittest.assertEquals(self.localWindowLeft, 4) - unittest.assert_(self.eofCalled) - log.msg('finished echo') - self.conn.addResult() - return 1 - - class SSHTestErrChannel(channel.SSHChannel): - - name = 'session' - testBuf = '' - eofCalled = 0 - - def openFailed(self, reason): - unittest.fail('err open failed: %s' % reason) - - def channelOpen(self, ignore): - d = self.conn.sendRequest(self, 'exec', common.NS('eecho hello'), 1) - d.addErrback(self._ebRequestFailed) - log.msg('opened err') - - def _ebRequestFailed(self, reason): - unittest.fail('err exec failed: %s' % reason) - - def dataReceived(self, data): - unittest.fail('err channel got regular data: %s' % repr(data)) def extReceived(self, dataType, data): - unittest.assertEquals(dataType, connection.EXTENDED_DATA_STDERR) - self.testBuf += data - - def request_exit_status(self, status): - self.status ,= struct.unpack('>L', status) - - def eofReceived(self): - log.msg('eof received') - self.eofCalled = 1 - - def closed(self): - if self.status != 0: - unittest.fail('err exit status was not 0: %i' % self.status) - if self.testBuf != "hello\r\n": - unittest.fail('err did not return hello: %s' % repr(self.testBuf)) - unittest.assertEquals(self.localWindowLeft, 4) - unittest.assert_(self.eofCalled) - log.msg('finished err') - self.conn.addResult() - return 1 - - class SSHTestMaxPacketChannel(channel.SSHChannel): - - name = 'session' - testBuf = '' - testExtBuf = '' - eofCalled = 0 - - def openFailed(self, reason): - unittest.fail('max packet open failed: %s' % reason) - - def channelOpen(self, ignore): - d = self.conn.sendRequest(self, 'exec', common.NS('secho hello'), 1) - d.addErrback(self._ebRequestFailed) - log.msg('opened max packet') - - def _ebRequestFailed(self, reason): - unittest.fail('max packet exec failed: %s' % reason) + if dataType == connection.EXTENDED_DATA_STDERR: + self.receivedExt.append(data) + else: + log.msg("Unrecognized extended data: %r" % (dataType,)) - def dataReceived(self, data): - self.testBuf += data - - def extReceived(self, dataType, data): - unittest.assertEquals(dataType, connection.EXTENDED_DATA_STDERR) - self.testExtBuf += data def request_exit_status(self, status): - self.status ,= struct.unpack('>L', status) + [self.status] = struct.unpack('>L', status) - def eofReceived(self): - log.msg('eof received') - self.eofCalled = 1 - - def closed(self): - if self.status != 0: - unittest.fail('echo exit status was not 0: %i' % self.status) - unittest.assertEquals(self.testBuf, 'hello\r\n') - unittest.assertEquals(self.testExtBuf, 'hello\r\n') - unittest.assertEquals(self.localWindowLeft, 12) - unittest.assert_(self.eofCalled) - log.msg('finished max packet') - self.conn.addResult() - return 1 - - class SSHTestShellChannel(channel.SSHChannel): - - name = 'session' - testBuf = '' - eofCalled = 0 - closeCalled = 0 - - def openFailed(self, reason): - unittest.fail('shell open failed: %s' % reason) - - def channelOpen(self, ignored): - data = session.packRequest_pty_req('conch-test-term', (24, 80, 0, 0), '') - d = self.conn.sendRequest(self, 'pty-req', data, 1) - d.addCallback(self._cbPtyReq) - d.addErrback(self._ebPtyReq) - log.msg('opened shell') - - def _cbPtyReq(self, ignored): - d = self.conn.sendRequest(self, 'shell', '', 1) - d.addCallback(self._cbShellOpen) - d.addErrback(self._ebShellOpen) - - def _ebPtyReq(self, reason): - unittest.fail('pty request failed: %s' % reason) - - def _cbShellOpen(self, ignored): - self.write('testing the shell!\x00') - self.conn.sendEOF(self) - - def _ebShellOpen(self, reason): - unittest.fail('shell request failed: %s' % reason) - - def dataReceived(self, data): - self.testBuf += data - - def request_exit_status(self, status): - self.status ,= struct.unpack('>L', status) def eofReceived(self): - self.eofCalled = 1 - - def closed(self): - log.msg('calling shell closed') - if self.status != 0: - log.msg('shell exit status was not 0: %i' % self.status) - unittest.assertEquals(self.testBuf, 'testing the shell!\x00\r\n') - unittest.assert_(self.eofCalled) - log.msg('finished shell') - self.conn.addResult() - - class SSHTestSubsystemChannel(channel.SSHChannel): - - name = 'session' - - def openFailed(self, reason): - unittest.fail('subsystem open failed: %s' % reason) + self.eofCalled = True - def channelOpen(self, ignore): - d = self.conn.sendRequest(self, 'subsystem', common.NS('not-crazy'), 1) - d.addCallback(self._cbRequestWorked) - d.addErrback(self._ebRequestFailed) - - - def _cbRequestWorked(self, ignored): - unittest.fail('opened non-crazy subsystem') - - def _ebRequestFailed(self, ignored): - d = self.conn.sendRequest(self, 'subsystem', common.NS('crazy'), 1) - d.addCallback(self._cbRealRequestWorked) - d.addErrback(self._ebRealRequestFailed) - - def _cbRealRequestWorked(self, ignored): - d1 = self.conn.sendGlobalRequest('foo', 'bar', 1) - d1.addErrback(self._ebFirstGlobal) - - d2 = self.conn.sendGlobalRequest('foo-2', 'bar2', 1) - d2.addCallback(lambda x: unittest.assertEquals(x, 'data')) - d2.addErrback(self._ebSecondGlobal) - - d3 = self.conn.sendGlobalRequest('bar', 'foo', 1) - d3.addCallback(self._cbThirdGlobal) - d3.addErrback(lambda x,s=self: log.msg('subsystem finished') or s.conn.addResult() or s.loseConnection()) - - def _ebRealRequestFailed(self, reason): - unittest.fail('opening crazy subsystem failed: %s' % reason) - - def _ebFirstGlobal(self, reason): - unittest.fail('first global request failed: %s' % reason) - - def _ebSecondGlobal(self, reason): - unittest.fail('second global request failed: %s' % reason) - def _cbThirdGlobal(self, ignored): - unittest.fail('second global request succeeded') + def closed(self): + self.onClose.callback(None) class SSHProtocolTestCase(unittest.TestCase): + """ + Tests for communication between L{SSHServerTransport} and + L{SSHClientTransport}. + """ if not Crypto: skip = "can't run w/o PyCrypto" if not pyasn1: - skip = "can't run w/o PyASN1" + skip = "Cannot run without PyASN1" - def test_ourServerOurClient(self): + def _ourServerOurClientTest(self, name='session', **kwargs): """ - Run the Conch server against the Conch client. Set up several different - channels which exercise different behaviors and wait for them to - complete. Verify that the channels with errors log them. + Create a connected SSH client and server protocol pair and return a + L{Deferred} which fires with an L{SSHTestChannel} instance connected to + a channel on that SSH connection. """ - realm = ConchTestRealm() - p = portal.Portal(realm) + result = defer.Deferred() + self.realm = ConchTestRealm('testuser') + p = portal.Portal(self.realm) sshpc = ConchTestSSHChecker() sshpc.registerChecker(ConchTestPasswordChecker()) sshpc.registerChecker(ConchTestPublicKeyChecker()) @@ -781,38 +556,266 @@ fac.startFactory() self.server = fac.buildProtocol(None) self.clientTransport = LoopbackRelay(self.server) - self.client = ConchTestClient() + self.client = ConchTestClient( + lambda conn: SSHTestChannel(name, result, conn=conn, **kwargs)) + self.serverTransport = LoopbackRelay(self.client) self.server.makeConnection(self.serverTransport) self.client.makeConnection(self.clientTransport) + return result - while self.serverTransport.buffer or self.clientTransport.buffer: - log.callWithContext({'system': 'serverTransport'}, - self.serverTransport.clearBuffer) - log.callWithContext({'system': 'clientTransport'}, - self.clientTransport.clearBuffer) - self.assertFalse(self.server.done and self.client.done) - - return self.client.completed.addCallback(self._verifyExpectedErrors) - - def _verifyExpectedErrors(self, ignored): - """ - Verify errors of the current test case are as many as we expect and the - ones we expect. - """ - errors = self.flushLoggedErrors(error.ConchError) - errors.sort(key=lambda reason: reason.value.args) - - # Two errors exactly are expected. Report the whole list if we get a - # different number. - self.assertEquals( - len(errors), 2, "Expected two errors, got: %r" % (errors,)) - - # SSHUnknownChannel causes this to be logged. - self.assertEquals(errors[0].value.args, (3, 'unknown channel')) - # SSHTestFailExecChannel causes this to be logged. - self.assertEquals(errors[1].value.args, ('bad exec', None)) + + def test_subsystemsAndGlobalRequests(self): + """ + Run the Conch server against the Conch client. Set up several different + channels which exercise different behaviors and wait for them to + complete. Verify that the channels with errors log them. + """ + channel = self._ourServerOurClientTest() + + def cbSubsystem(channel): + self.channel = channel + return self.assertFailure( + channel.conn.sendRequest( + channel, 'subsystem', common.NS('not-crazy'), 1), + Exception) + channel.addCallback(cbSubsystem) + + def cbNotCrazyFailed(ignored): + channel = self.channel + return channel.conn.sendRequest( + channel, 'subsystem', common.NS('crazy'), 1) + channel.addCallback(cbNotCrazyFailed) + + def cbGlobalRequests(ignored): + channel = self.channel + d1 = channel.conn.sendGlobalRequest('foo', 'bar', 1) + + d2 = channel.conn.sendGlobalRequest('foo-2', 'bar2', 1) + d2.addCallback(self.assertEqual, 'data') + + d3 = self.assertFailure( + channel.conn.sendGlobalRequest('bar', 'foo', 1), + Exception) + + return defer.gatherResults([d1, d2, d3]) + channel.addCallback(cbGlobalRequests) + + def disconnect(ignored): + self.assertEqual( + self.realm.avatar.globalRequests, + {"foo": "bar", "foo_2": "bar2"}) + channel = self.channel + channel.conn.transport.expectedLoseConnection = True + channel.conn.serviceStopped() + channel.loseConnection() + channel.addCallback(disconnect) + + return channel + + + def test_shell(self): + """ + L{SSHChannel.sendRequest} can open a shell with a I{pty-req} request, + specifying a terminal type and window size. + """ + channel = self._ourServerOurClientTest() + + data = session.packRequest_pty_req('conch-test-term', (24, 80, 0, 0), '') + def cbChannel(channel): + self.channel = channel + return channel.conn.sendRequest(channel, 'pty-req', data, 1) + channel.addCallback(cbChannel) + + def cbPty(ignored): + # The server-side object corresponding to our client side channel. + session = self.realm.avatar.conn.channels[0].session + self.assertIdentical(session.avatar, self.realm.avatar) + self.assertEqual(session._terminalType, 'conch-test-term') + self.assertEqual(session._windowSize, (24, 80, 0, 0)) + self.assertTrue(session.ptyReq) + channel = self.channel + return channel.conn.sendRequest(channel, 'shell', '', 1) + channel.addCallback(cbPty) + + def cbShell(ignored): + self.channel.write('testing the shell!\x00') + self.channel.conn.sendEOF(self.channel) + return defer.gatherResults([ + self.channel.onClose, + self.realm.avatar._testSession.onClose]) + channel.addCallback(cbShell) + + def cbExited(ignored): + if self.channel.status != 0: + log.msg( + 'shell exit status was not 0: %i' % (self.channel.status,)) + self.assertEqual( + "".join(self.channel.received), + 'testing the shell!\x00\r\n') + self.assertTrue(self.channel.eofCalled) + self.assertTrue( + self.realm.avatar._testSession.eof) + channel.addCallback(cbExited) + return channel + + + def test_failedExec(self): + """ + If L{SSHChannel.sendRequest} issues an exec which the server responds to + with an error, the L{Deferred} it returns fires its errback. + """ + channel = self._ourServerOurClientTest() + + def cbChannel(channel): + self.channel = channel + return self.assertFailure( + channel.conn.sendRequest( + channel, 'exec', common.NS('jumboliah'), 1), + Exception) + channel.addCallback(cbChannel) + + def cbFailed(ignored): + # The server logs this exception when it cannot perform the + # requested exec. + errors = self.flushLoggedErrors(error.ConchError) + self.assertEqual(errors[0].value.args, ('bad exec', None)) + channel.addCallback(cbFailed) + return channel + + + def test_falseChannel(self): + """ + When the process started by a L{SSHChannel.sendRequest} exec request + exits, the exit status is reported to the channel. + """ + channel = self._ourServerOurClientTest() + + def cbChannel(channel): + self.channel = channel + return channel.conn.sendRequest( + channel, 'exec', common.NS('false'), 1) + channel.addCallback(cbChannel) + + def cbExec(ignored): + return self.channel.onClose + channel.addCallback(cbExec) + + def cbClosed(ignored): + # No data is expected + self.assertEqual(self.channel.received, []) + self.assertNotEquals(self.channel.status, 0) + channel.addCallback(cbClosed) + return channel + + + def test_errorChannel(self): + """ + Bytes sent over the extended channel for stderr data are delivered to + the channel's C{extReceived} method. + """ + channel = self._ourServerOurClientTest(localWindow=4, localMaxPacket=5) + + def cbChannel(channel): + self.channel = channel + return channel.conn.sendRequest( + channel, 'exec', common.NS('eecho hello'), 1) + channel.addCallback(cbChannel) + + def cbExec(ignored): + return defer.gatherResults([ + self.channel.onClose, + self.realm.avatar._testSession.onClose]) + channel.addCallback(cbExec) + + def cbClosed(ignored): + self.assertEqual(self.channel.received, []) + self.assertEqual("".join(self.channel.receivedExt), "hello\r\n") + self.assertEqual(self.channel.status, 0) + self.assertTrue(self.channel.eofCalled) + self.assertEqual(self.channel.localWindowLeft, 4) + self.assertEqual( + self.channel.localWindowLeft, + self.realm.avatar._testSession.remoteWindowLeftAtClose) + channel.addCallback(cbClosed) + return channel + + + def test_unknownChannel(self): + """ + When an attempt is made to open an unknown channel type, the L{Deferred} + returned by L{SSHChannel.sendRequest} fires its errback. + """ + d = self.assertFailure( + self._ourServerOurClientTest('crazy-unknown-channel'), Exception) + def cbFailed(ignored): + errors = self.flushLoggedErrors(error.ConchError) + self.assertEqual(errors[0].value.args, (3, 'unknown channel')) + self.assertEqual(len(errors), 1) + d.addCallback(cbFailed) + return d + + + def test_maxPacket(self): + """ + An L{SSHChannel} can be configured with a maximum packet size to + receive. + """ + # localWindow needs to be at least 11 otherwise the assertion about it + # in cbClosed is invalid. + channel = self._ourServerOurClientTest( + localWindow=11, localMaxPacket=1) + + def cbChannel(channel): + self.channel = channel + return channel.conn.sendRequest( + channel, 'exec', common.NS('secho hello'), 1) + channel.addCallback(cbChannel) + + def cbExec(ignored): + return self.channel.onClose + channel.addCallback(cbExec) + + def cbClosed(ignored): + self.assertEqual(self.channel.status, 0) + self.assertEqual("".join(self.channel.received), "hello\r\n") + self.assertEqual("".join(self.channel.receivedExt), "hello\r\n") + self.assertEqual(self.channel.localWindowLeft, 11) + self.assertTrue(self.channel.eofCalled) + channel.addCallback(cbClosed) + return channel + + + def test_echo(self): + """ + Normal standard out bytes are sent to the channel's C{dataReceived} + method. + """ + channel = self._ourServerOurClientTest(localWindow=4, localMaxPacket=5) + + def cbChannel(channel): + self.channel = channel + return channel.conn.sendRequest( + channel, 'exec', common.NS('echo hello'), 1) + channel.addCallback(cbChannel) + + def cbEcho(ignored): + return defer.gatherResults([ + self.channel.onClose, + self.realm.avatar._testSession.onClose]) + channel.addCallback(cbEcho) + + def cbClosed(ignored): + self.assertEqual(self.channel.status, 0) + self.assertEqual("".join(self.channel.received), "hello\r\n") + self.assertEqual(self.channel.localWindowLeft, 4) + self.assertTrue(self.channel.eofCalled) + self.assertEqual( + self.channel.localWindowLeft, + self.realm.avatar._testSession.remoteWindowLeftAtClose) + channel.addCallback(cbClosed) + return channel @@ -822,7 +825,7 @@ skip = "can't run w/o PyCrypto" if not pyasn1: - skip = "can't run w/o PyASN1" + skip = "Cannot run without PyASN1" def makeSSHFactory(self, primes=None): sshFactory = factory.SSHFactory() @@ -855,7 +858,7 @@ factory = self.makeSSHFactory() factory.protocol = makeProtocol factory.buildProtocol(None) - self.assertEquals([()], calls) + self.assertEqual([()], calls) def test_multipleFactories(self): @@ -883,7 +886,7 @@ skip = "can't run w/o PyCrypto" if not pyasn1: - skip = "can't run w/o PyASN1" + skip = "Cannot run without PyASN1" def test_getMP(self): @@ -891,7 +894,7 @@ L{common.getMP} should parse the a multiple precision integer from a string: a 4-byte length followed by length bytes of the integer. """ - self.assertEquals( + self.assertEqual( self.getMP('\x00\x00\x00\x04\x00\x00\x00\x01'), (1, '')) @@ -901,7 +904,7 @@ L{common.getMP} should be able to parse a big enough integer (that doesn't fit on one byte). """ - self.assertEquals( + self.assertEqual( self.getMP('\x00\x00\x00\x04\x01\x02\x03\x04'), (16909060, '')) @@ -911,7 +914,7 @@ L{common.getMP} has the ability to parse multiple integer in the same string. """ - self.assertEquals( + self.assertEqual( self.getMP('\x00\x00\x00\x04\x00\x00\x00\x01' '\x00\x00\x00\x04\x00\x00\x00\x02', 2), (1, 2, '')) @@ -922,7 +925,7 @@ When more data than needed is sent to L{common.getMP}, it should return the remaining data. """ - self.assertEquals( + self.assertEqual( self.getMP('\x00\x00\x00\x04\x00\x00\x00\x01foo'), (1, 'foo')) @@ -951,8 +954,42 @@ getMP = staticmethod(common._fastgetMP) +class BuiltinPowHackTestCase(unittest.TestCase): + """ + Tests that the builtin pow method is still correct after + L{twisted.conch.ssh.common} monkeypatches it to use gmpy. + """ + + def test_floatBase(self): + """ + pow gives the correct result when passed a base of type float with a + non-integer value. + """ + self.assertEqual(6.25, pow(2.5, 2)) + + def test_intBase(self): + """ + pow gives the correct result when passed a base of type int. + """ + self.assertEqual(81, pow(3, 4)) + + def test_longBase(self): + """ + pow gives the correct result when passed a base of type long. + """ + self.assertEqual(81, pow(3, 4)) + + def test_mpzBase(self): + """ + pow gives the correct result when passed a base of type gmpy.mpz. + """ + if gmpy is None: + raise unittest.SkipTest('gmpy not available') + self.assertEqual(81, pow(gmpy.mpz(3), 4)) + try: import gmpy except ImportError: GMPYMPTestCase.skip = "gmpy not available" + gmpy = None diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_tap.py twisted-conch-12.1.0/twisted/conch/test/test_tap.py --- twisted-conch-10.2.0/twisted/conch/test/test_tap.py 2010-10-19 01:18:12.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_tap.py 2012-03-12 21:35:11.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -26,9 +26,10 @@ from twisted.python.compat import set from twisted.application.internet import StreamServerEndpointService +from twisted.cred import error from twisted.cred.credentials import IPluggableAuthenticationModules from twisted.cred.credentials import ISSHPrivateKey -from twisted.cred.credentials import IUsernamePassword +from twisted.cred.credentials import IUsernamePassword, UsernamePassword from twisted.trial.unittest import TestCase @@ -43,11 +44,24 @@ skip = "can't run w/o PyCrypto" if not pyasn1: - skip = "can't run w/o PyASN1" + skip = "Cannot run without PyASN1" if not unix: skip = "can't run on non-posix computers" + usernamePassword = ('iamuser', 'thisispassword') + + def setUp(self): + """ + Create a file with two users. + """ + self.filename = self.mktemp() + f = open(self.filename, 'wb+') + f.write(':'.join(self.usernamePassword)) + f.close() + self.options = tap.Options() + + def test_basic(self): """ L{tap.makeService} returns a L{StreamServerEndpointService} instance @@ -57,10 +71,74 @@ config = tap.Options() service = tap.makeService(config) self.assertIsInstance(service, StreamServerEndpointService) - self.assertEquals(service.endpoint._port, 22) + self.assertEqual(service.endpoint._port, 22) self.assertIsInstance(service.factory, OpenSSHFactory) + def test_defaultAuths(self): + """ + Make sure that if the C{--auth} command-line option is not passed, + the default checkers are (for backwards compatibility): SSH, UNIX, and + PAM if available + """ + numCheckers = 2 + try: + from twisted.cred import pamauth + self.assertIn(IPluggableAuthenticationModules, + self.options['credInterfaces'], + "PAM should be one of the modules") + numCheckers += 1 + except ImportError: + pass + + self.assertIn(ISSHPrivateKey, self.options['credInterfaces'], + "SSH should be one of the default checkers") + self.assertIn(IUsernamePassword, self.options['credInterfaces'], + "UNIX should be one of the default checkers") + self.assertEqual(numCheckers, len(self.options['credCheckers']), + "There should be %d checkers by default" % (numCheckers,)) + + + def test_authAdded(self): + """ + The C{--auth} command-line option will add a checker to the list of + checkers, and it should be the only auth checker + """ + self.options.parseOptions(['--auth', 'file:' + self.filename]) + self.assertEqual(len(self.options['credCheckers']), 1) + + + def test_authFailure(self): + """ + The checker created by the C{--auth} command-line option returns a + L{Deferred} that fails with L{UnauthorizedLogin} when + presented with credentials that are unknown to that checker. + """ + self.options.parseOptions(['--auth', 'file:' + self.filename]) + checker = self.options['credCheckers'][-1] + invalid = UsernamePassword(self.usernamePassword[0], 'fake') + # Wrong password should raise error + return self.assertFailure( + checker.requestAvatarId(invalid), error.UnauthorizedLogin) + + + def test_authSuccess(self): + """ + The checker created by the C{--auth} command-line option returns a + L{Deferred} that returns the avatar id when presented with credentials + that are known to that checker. + """ + self.options.parseOptions(['--auth', 'file:' + self.filename]) + checker = self.options['credCheckers'][-1] + correct = UsernamePassword(*self.usernamePassword) + d = checker.requestAvatarId(correct) + + def checkSuccess(username): + self.assertEqual(username, correct.username) + + return d.addCallback(checkSuccess) + + def test_checkersPamAuth(self): """ The L{OpenSSHFactory} built by L{tap.makeService} has a portal with @@ -73,7 +151,7 @@ config = tap.Options() service = tap.makeService(config) portal = service.factory.portal - self.assertEquals( + self.assertEqual( set(portal.checkers.keys()), set([IPluggableAuthenticationModules, ISSHPrivateKey, IUsernamePassword])) @@ -90,6 +168,6 @@ config = tap.Options() service = tap.makeService(config) portal = service.factory.portal - self.assertEquals( + self.assertEqual( set(portal.checkers.keys()), set([ISSHPrivateKey, IUsernamePassword])) diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_telnet.py twisted-conch-12.1.0/twisted/conch/test/test_telnet.py --- twisted-conch-10.2.0/twisted/conch/test/test_telnet.py 2010-10-07 23:27:52.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_telnet.py 2011-10-01 08:11:41.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_telnet -*- -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -7,6 +7,7 @@ """ from zope.interface import implements +from zope.interface.verify import verifyObject from twisted.internet import defer @@ -69,6 +70,16 @@ +class TestInterfaces(unittest.TestCase): + def test_interface(self): + """ + L{telnet.TelnetProtocol} implements L{telnet.ITelnetProtocol} + """ + p = telnet.TelnetProtocol() + verifyObject(telnet.ITelnetProtocol, p) + + + class TelnetTransportTestCase(unittest.TestCase): """ Tests for L{telnet.TelnetTransport}. @@ -93,7 +104,7 @@ for b in L: self.p.dataReceived(b) - self.assertEquals(h.bytes, ''.join(L)) + self.assertEqual(h.bytes, ''.join(L)) def testNewlineHandling(self): # Send various kinds of newlines and make sure they get translated @@ -108,7 +119,7 @@ for b in L: self.p.dataReceived(b) - self.assertEquals(h.bytes, L[0][:-2] + '\n' + + self.assertEqual(h.bytes, L[0][:-2] + '\n' + L[1][:-2] + '\r' + L[2][:-2] + '\n' + L[3][:-2] + '\r') @@ -126,7 +137,7 @@ for b in L: self.p.dataReceived(b) - self.assertEquals(h.bytes, ''.join(L).replace('\xff\xff', '\xff')) + self.assertEqual(h.bytes, ''.join(L).replace('\xff\xff', '\xff')) def _simpleCommandTest(self, cmdName): # Send a single simple telnet command and make sure @@ -141,8 +152,8 @@ for b in L: self.p.dataReceived(b) - self.assertEquals(h.calls, [cmdName]) - self.assertEquals(h.bytes, ''.join(L).replace(cmd, '')) + self.assertEqual(h.calls, [cmdName]) + self.assertEqual(h.bytes, ''.join(L).replace(cmd, '')) def testInterrupt(self): self._simpleCommandTest("IP") @@ -183,8 +194,8 @@ for b in L: self.p.dataReceived(b) - self.assertEquals(h.bytes, ''.join(L).replace(cmd, '')) - self.assertEquals(h.subcmd, list("hello world")) + self.assertEqual(h.bytes, ''.join(L).replace(cmd, '')) + self.assertEqual(h.subcmd, list("hello world")) def testSubnegotiationWithEmbeddedSE(self): # Send a subnegotiation command with an embedded SE. Make sure @@ -201,8 +212,8 @@ for b in L: self.p.dataReceived(b) - self.assertEquals(h.bytes, ''.join(L).replace(cmd, '')) - self.assertEquals(h.subcmd, [telnet.SE]) + self.assertEqual(h.bytes, ''.join(L).replace(cmd, '')) + self.assertEqual(h.subcmd, [telnet.SE]) def testBoundarySubnegotiation(self): # Send a subnegotiation command. Split it at every possible byte boundary @@ -223,14 +234,14 @@ for bytes in L: self.p.dataReceived(bytes) - self.assertEquals(h.bytes, ''.join(L).replace(cmd, '')) - self.assertEquals(h.subcmd, [telnet.SE] + list('hello')) + self.assertEqual(h.bytes, ''.join(L).replace(cmd, '')) + self.assertEqual(h.subcmd, [telnet.SE] + list('hello')) def _enabledHelper(self, o, eL=[], eR=[], dL=[], dR=[]): - self.assertEquals(o.enabledLocal, eL) - self.assertEquals(o.enabledRemote, eR) - self.assertEquals(o.disabledLocal, dL) - self.assertEquals(o.disabledRemote, dR) + self.assertEqual(o.enabledLocal, eL) + self.assertEqual(o.enabledRemote, eR) + self.assertEqual(o.disabledLocal, dL) + self.assertEqual(o.disabledRemote, dR) def testRefuseWill(self): # Try to enable an option. The server should refuse to enable it. @@ -239,8 +250,8 @@ bytes = "surrounding bytes" + cmd + "to spice things up" self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), telnet.IAC + telnet.DONT + '\x12') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), telnet.IAC + telnet.DONT + '\x12') self._enabledHelper(self.p.protocol) def testRefuseDo(self): @@ -250,8 +261,8 @@ bytes = "surrounding bytes" + cmd + "to spice things up" self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), telnet.IAC + telnet.WONT + '\x12') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), telnet.IAC + telnet.WONT + '\x12') self._enabledHelper(self.p.protocol) def testAcceptDo(self): @@ -264,7 +275,7 @@ h.localEnableable = ('\x19',) self.p.dataReceived(bytes) - self.assertEquals(self.t.value(), telnet.IAC + telnet.WILL + '\x19') + self.assertEqual(self.t.value(), telnet.IAC + telnet.WILL + '\x19') self._enabledHelper(h, eL=['\x19']) def testAcceptWill(self): @@ -276,7 +287,7 @@ h.remoteEnableable = ('\x91',) self.p.dataReceived(bytes) - self.assertEquals(self.t.value(), telnet.IAC + telnet.DO + '\x91') + self.assertEqual(self.t.value(), telnet.IAC + telnet.DO + '\x91') self._enabledHelper(h, eR=['\x91']) def testAcceptWont(self): @@ -294,9 +305,9 @@ bytes = "fiddle dee" + cmd self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), telnet.IAC + telnet.DONT + '\x29') - self.assertEquals(s.him.state, 'no') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), telnet.IAC + telnet.DONT + '\x29') + self.assertEqual(s.him.state, 'no') self._enabledHelper(self.p.protocol, dR=['\x29']) def testAcceptDont(self): @@ -314,9 +325,9 @@ bytes = "fiddle dum " + cmd self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), telnet.IAC + telnet.WONT + '\x29') - self.assertEquals(s.us.state, 'no') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), telnet.IAC + telnet.WONT + '\x29') + self.assertEqual(s.us.state, 'no') self._enabledHelper(self.p.protocol, dL=['\x29']) def testIgnoreWont(self): @@ -327,8 +338,8 @@ bytes = "dum de dum" + cmd + "tra la la" self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), '') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), '') self._enabledHelper(self.p.protocol) def testIgnoreDont(self): @@ -340,8 +351,8 @@ bytes = "dum de dum" + cmd + "tra la la" self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), '') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), '') self._enabledHelper(self.p.protocol) def testIgnoreWill(self): @@ -359,8 +370,8 @@ bytes = "tra la la" + cmd + "dum de dum" self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), '') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), '') self._enabledHelper(self.p.protocol) def testIgnoreDo(self): @@ -378,8 +389,8 @@ bytes = "tra la la" + cmd + "dum de dum" self.p.dataReceived(bytes) - self.assertEquals(self.p.protocol.bytes, bytes.replace(cmd, '')) - self.assertEquals(self.t.value(), '') + self.assertEqual(self.p.protocol.bytes, bytes.replace(cmd, '')) + self.assertEqual(self.t.value(), '') self._enabledHelper(self.p.protocol) def testAcceptedEnableRequest(self): @@ -392,11 +403,11 @@ h = self.p.protocol h.remoteEnableable = ('\x42',) - self.assertEquals(self.t.value(), telnet.IAC + telnet.DO + '\x42') + self.assertEqual(self.t.value(), telnet.IAC + telnet.DO + '\x42') self.p.dataReceived(telnet.IAC + telnet.WILL + '\x42') - d.addCallback(self.assertEquals, True) + d.addCallback(self.assertEqual, True) d.addCallback(lambda _: self._enabledHelper(h, eR=['\x42'])) return d @@ -414,20 +425,20 @@ self.p.protocol.remoteEnableable = ('\x42',) d = self.p.do('\x42') - self.assertEquals(self.t.value(), telnet.IAC + telnet.DO + '\x42') + self.assertEqual(self.t.value(), telnet.IAC + telnet.DO + '\x42') s = self.p.getOptionState('\x42') - self.assertEquals(s.him.state, 'no') - self.assertEquals(s.us.state, 'no') - self.assertEquals(s.him.negotiating, True) - self.assertEquals(s.us.negotiating, False) + self.assertEqual(s.him.state, 'no') + self.assertEqual(s.us.state, 'no') + self.assertEqual(s.him.negotiating, True) + self.assertEqual(s.us.negotiating, False) self.p.dataReceived(telnet.IAC + telnet.WONT + '\x42') d = self.assertFailure(d, telnet.OptionRefused) d.addCallback(lambda ignored: self._enabledHelper(self.p.protocol)) d.addCallback( - lambda ignored: self.assertEquals(s.him.negotiating, False)) + lambda ignored: self.assertEqual(s.him.negotiating, False)) return d @@ -444,20 +455,20 @@ self.p.protocol.localEnableable = ('\x42',) d = self.p.will('\x42') - self.assertEquals(self.t.value(), telnet.IAC + telnet.WILL + '\x42') + self.assertEqual(self.t.value(), telnet.IAC + telnet.WILL + '\x42') s = self.p.getOptionState('\x42') - self.assertEquals(s.him.state, 'no') - self.assertEquals(s.us.state, 'no') - self.assertEquals(s.him.negotiating, False) - self.assertEquals(s.us.negotiating, True) + self.assertEqual(s.him.state, 'no') + self.assertEqual(s.us.state, 'no') + self.assertEqual(s.him.negotiating, False) + self.assertEqual(s.us.negotiating, True) self.p.dataReceived(telnet.IAC + telnet.DONT + '\x42') d = self.assertFailure(d, telnet.OptionRefused) d.addCallback(lambda ignored: self._enabledHelper(self.p.protocol)) d.addCallback( - lambda ignored: self.assertEquals(s.us.negotiating, False)) + lambda ignored: self.assertEqual(s.us.negotiating, False)) return d @@ -471,11 +482,11 @@ d = self.p.dont('\x42') - self.assertEquals(self.t.value(), telnet.IAC + telnet.DONT + '\x42') + self.assertEqual(self.t.value(), telnet.IAC + telnet.DONT + '\x42') self.p.dataReceived(telnet.IAC + telnet.WONT + '\x42') - d.addCallback(self.assertEquals, True) + d.addCallback(self.assertEqual, True) d.addCallback(lambda _: self._enabledHelper(self.p.protocol, dR=['\x42'])) return d @@ -504,7 +515,7 @@ self.p.protocol.remoteEnableable = ('\x24',) d = self.p.do('\x24') self.p.dataReceived(telnet.IAC + telnet.WILL + '\x24') - d.addCallback(self.assertEquals, True) + d.addCallback(self.assertEqual, True) d.addCallback(lambda _: self._enabledHelper(self.p.protocol, eR=['\x24'], dR=['\x24'])) diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_text.py twisted-conch-12.1.0/twisted/conch/test/test_text.py --- twisted-conch-10.2.0/twisted/conch/test/test_text.py 2006-10-08 22:23:48.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_text.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_text -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.trial import unittest @@ -13,46 +13,46 @@ self.attrs = helper.CharacterAttribute() def testTrivial(self): - self.assertEquals( + self.assertEqual( text.flatten(A.normal['Hello, world.'], self.attrs), 'Hello, world.') def testBold(self): - self.assertEquals( + self.assertEqual( text.flatten(A.bold['Hello, world.'], self.attrs), '\x1b[1mHello, world.') def testUnderline(self): - self.assertEquals( + self.assertEqual( text.flatten(A.underline['Hello, world.'], self.attrs), '\x1b[4mHello, world.') def testBlink(self): - self.assertEquals( + self.assertEqual( text.flatten(A.blink['Hello, world.'], self.attrs), '\x1b[5mHello, world.') def testReverseVideo(self): - self.assertEquals( + self.assertEqual( text.flatten(A.reverseVideo['Hello, world.'], self.attrs), '\x1b[7mHello, world.') def testMinus(self): - self.assertEquals( + self.assertEqual( text.flatten( A.bold[A.blink['Hello', -A.bold[' world'], '.']], self.attrs), '\x1b[1;5mHello\x1b[0;5m world\x1b[1;5m.') def testForeground(self): - self.assertEquals( + self.assertEqual( text.flatten( A.normal[A.fg.red['Hello, '], A.fg.green['world!']], self.attrs), '\x1b[31mHello, \x1b[32mworld!') def testBackground(self): - self.assertEquals( + self.assertEqual( text.flatten( A.normal[A.bg.red['Hello, '], A.bg.green['world!']], self.attrs), @@ -82,7 +82,7 @@ A.fg.green[ "Foreground Green, Background Cyan, Bold"]]]] - self.assertEquals( + self.assertEqual( text.flatten(output, self.attrs), "\x1b[1;31;46mForeground Red, Background Cyan, Bold" "\x1b[5mBlinking" @@ -90,11 +90,11 @@ "\x1b[1;32;46mForeground Green, Background Cyan, Bold") def testNesting(self): - self.assertEquals( + self.assertEqual( text.flatten(A.bold['Hello, ', A.underline['world.']], self.attrs), '\x1b[1mHello, \x1b[4mworld.') - self.assertEquals( + self.assertEqual( text.flatten( A.bold[A.reverseVideo['Hello, ', A.normal['world'], '.']], self.attrs), diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_transport.py twisted-conch-12.1.0/twisted/conch/test/test_transport.py --- twisted-conch-10.2.0/twisted/conch/test/test_transport.py 2010-07-08 17:01:47.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_transport.py 2012-01-15 02:23:55.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -17,11 +17,11 @@ if pyasn1 is not None and Crypto is not None: dependencySkip = None - from twisted.conch.ssh import transport, common, keys, factory + from twisted.conch.ssh import transport, keys, factory from twisted.conch.test import keydata else: if pyasn1 is None: - dependencySkip = "can't run w/o PyASN1" + dependencySkip = "Cannot run without PyASN1" elif Crypto is None: dependencySkip = "can't run w/o PyCrypto" @@ -39,7 +39,7 @@ 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.conch.ssh import service, common from twisted.test import proto_helpers from twisted.conch.error import ConchError @@ -326,7 +326,7 @@ skip = "cannot run w/o PyCrypto" if pyasn1 is None: - skip = "cannot run w/o PyASN1" + skip = "Cannot run without PyASN1" def setUp(self): @@ -347,11 +347,40 @@ self.proto.sendPacket = stubSendPacket + def finishKeyExchange(self, proto): + """ + Deliver enough additional messages to C{proto} so that the key exchange + which is started in L{SSHTransportBase.connectionMade} completes and + non-key exchange messages can be sent and received. + """ + proto.dataReceived("SSH-2.0-BogoClient-1.2i\r\n") + proto.dispatchMessage( + transport.MSG_KEXINIT, self._A_KEXINIT_MESSAGE) + proto._keySetup("foo", "bar") + # SSHTransportBase can't handle MSG_NEWKEYS, or it would be the right + # thing to deliver next. _newKeys won't work either, because + # sendKexInit (probably) hasn't been called. sendKexInit is responsible + # for setting up certain state _newKeys relies on. So, just change the + # key exchange state to what it would be when key exchange is finished. + proto._keyExchangeState = proto._KEY_EXCHANGE_NONE + + def tearDown(self): randbytes.secureRandom = self.oldSecureRandom self.oldSecureRandom = None + def simulateKeyExchange(self, sharedSecret, exchangeHash): + """ + Finish a key exchange by calling C{_keySetup} with the given arguments. + Also do extra whitebox stuff to satisfy that method's assumption that + some kind of key exchange has actually taken place. + """ + self.proto._keyExchangeState = self.proto._KEY_EXCHANGE_REQUESTED + self.proto._blockedByKeyExchange = [] + self.proto._keySetup(sharedSecret, exchangeHash) + + class BaseSSHTransportTestCase(TransportTestCase): """ @@ -361,6 +390,19 @@ klass = MockTransportBase + _A_KEXINIT_MESSAGE = ( + "\xAA" * 16 + + common.NS('diffie-hellman-group1-sha1') + + common.NS('ssh-rsa') + + common.NS('aes256-ctr') + + common.NS('aes256-ctr') + + common.NS('hmac-sha1') + + common.NS('hmac-sha1') + + common.NS('none') + + common.NS('none') + + common.NS('') + + common.NS('') + + '\x00' + '\x00\x00\x00\x00') def test_sendVersion(self): """ @@ -368,7 +410,7 @@ string. """ # the other setup was done in the setup method - self.assertEquals(self.transport.value().split('\r\n', 1)[0], + self.assertEqual(self.transport.value().split('\r\n', 1)[0], "SSH-2.0-Twisted") @@ -384,12 +426,13 @@ """ proto = MockTransportBase() proto.makeConnection(self.transport) + self.finishKeyExchange(proto) self.transport.clear() message = ord('A') payload = 'BCDEFG' proto.sendPacket(message, payload) value = self.transport.value() - self.assertEquals(value, '\x00\x00\x00\x0c\x04ABCDEFG\x99\x99\x99\x99') + self.assertEqual(value, '\x00\x00\x00\x0c\x04ABCDEFG\x99\x99\x99\x99') def test_sendPacketEncrypted(self): @@ -399,6 +442,7 @@ """ proto = MockTransportBase() proto.makeConnection(self.transport) + self.finishKeyExchange(proto) proto.currentEncryptions = testCipher = MockCipher() message = ord('A') payload = 'BC' @@ -406,7 +450,18 @@ proto.sendPacket(message, payload) self.assertTrue(testCipher.usedEncrypt) value = self.transport.value() - self.assertEquals(value, '\x00\x00\x00\x08\x04ABC\x99\x99\x99\x99\x01') + self.assertEqual( + value, + # Four byte length prefix + '\x00\x00\x00\x08' + # One byte padding length + '\x04' + # The actual application data + 'ABC' + # "Random" padding - see the secureRandom monkeypatch in setUp + '\x99\x99\x99\x99' + # The MAC + '\x02') def test_sendPacketCompressed(self): @@ -416,11 +471,12 @@ """ proto = MockTransportBase() proto.makeConnection(self.transport) + self.finishKeyExchange(proto) proto.outgoingCompression = MockCompression() self.transport.clear() proto.sendPacket(ord('A'), 'B') value = self.transport.value() - self.assertEquals( + self.assertEqual( value, '\x00\x00\x00\x0c\x08BA\x66\x99\x99\x99\x99\x99\x99\x99\x99') @@ -433,17 +489,27 @@ """ proto = MockTransportBase() proto.makeConnection(self.transport) + self.finishKeyExchange(proto) proto.currentEncryptions = testCipher = MockCipher() proto.outgoingCompression = MockCompression() message = ord('A') payload = 'BC' self.transport.clear() proto.sendPacket(message, payload) + self.assertTrue(testCipher.usedEncrypt) value = self.transport.value() - self.assertEquals( + self.assertEqual( value, - '\x00\x00\x00\x0e\x09CBA\x66\x99\x99\x99\x99\x99\x99\x99\x99\x99' - '\x01') + # Four byte length prefix + '\x00\x00\x00\x0e' + # One byte padding length + '\x09' + # Compressed application data + 'CBA\x66' + # "Random" padding - see the secureRandom monkeypatch in setUp + '\x99\x99\x99\x99\x99\x99\x99\x99\x99' + # The MAC + '\x02') def test_getPacketPlain(self): @@ -453,11 +519,12 @@ """ proto = MockTransportBase() proto.makeConnection(self.transport) + self.finishKeyExchange(proto) self.transport.clear() proto.sendPacket(ord('A'), 'BC') proto.buf = self.transport.value() + 'extra' - self.assertEquals(proto.getPacket(), 'ABC') - self.assertEquals(proto.buf, 'extra') + self.assertEqual(proto.getPacket(), 'ABC') + self.assertEqual(proto.buf, 'extra') def test_getPacketEncrypted(self): @@ -473,12 +540,12 @@ proto.sendPacket(ord('A'), 'BCD') value = self.transport.value() proto.buf = value[:MockCipher.decBlockSize] - self.assertEquals(proto.getPacket(), None) + self.assertEqual(proto.getPacket(), None) self.assertTrue(testCipher.usedDecrypt) - self.assertEquals(proto.first, '\x00\x00\x00\x0e\x09A') + self.assertEqual(proto.first, '\x00\x00\x00\x0e\x09A') proto.buf += value[MockCipher.decBlockSize:] - self.assertEquals(proto.getPacket(), 'ABCD') - self.assertEquals(proto.buf, '') + self.assertEqual(proto.getPacket(), 'ABCD') + self.assertEqual(proto.buf, '') def test_getPacketCompressed(self): @@ -488,12 +555,13 @@ """ proto = MockTransportBase() proto.makeConnection(self.transport) + self.finishKeyExchange(proto) self.transport.clear() proto.outgoingCompression = MockCompression() proto.incomingCompression = proto.outgoingCompression proto.sendPacket(ord('A'), 'BCD') proto.buf = self.transport.value() - self.assertEquals(proto.getPacket(), 'ABCD') + self.assertEqual(proto.getPacket(), 'ABCD') def test_getPacketBoth(self): @@ -510,7 +578,7 @@ proto.incomingCompression = proto.outgoingCompression proto.sendPacket(ord('A'), 'BCDEFG') proto.buf = self.transport.value() - self.assertEquals(proto.getPacket(), 'ABCDEFG') + self.assertEqual(proto.getPacket(), 'ABCDEFG') def test_ciphersAreValid(self): @@ -542,25 +610,97 @@ value = self.transport.value().split('\r\n', 1)[1] self.proto.buf = value packet = self.proto.getPacket() - self.assertEquals(packet[0], chr(transport.MSG_KEXINIT)) - self.assertEquals(packet[1:17], '\x99' * 16) + self.assertEqual(packet[0], chr(transport.MSG_KEXINIT)) + self.assertEqual(packet[1:17], '\x99' * 16) (kex, pubkeys, ciphers1, ciphers2, macs1, macs2, compressions1, compressions2, languages1, languages2, buf) = common.getNS(packet[17:], 10) - self.assertEquals(kex, ','.join(self.proto.supportedKeyExchanges)) - self.assertEquals(pubkeys, ','.join(self.proto.supportedPublicKeys)) - self.assertEquals(ciphers1, ','.join(self.proto.supportedCiphers)) - self.assertEquals(ciphers2, ','.join(self.proto.supportedCiphers)) - self.assertEquals(macs1, ','.join(self.proto.supportedMACs)) - self.assertEquals(macs2, ','.join(self.proto.supportedMACs)) - self.assertEquals(compressions1, + self.assertEqual(kex, ','.join(self.proto.supportedKeyExchanges)) + self.assertEqual(pubkeys, ','.join(self.proto.supportedPublicKeys)) + self.assertEqual(ciphers1, ','.join(self.proto.supportedCiphers)) + self.assertEqual(ciphers2, ','.join(self.proto.supportedCiphers)) + self.assertEqual(macs1, ','.join(self.proto.supportedMACs)) + self.assertEqual(macs2, ','.join(self.proto.supportedMACs)) + self.assertEqual(compressions1, ','.join(self.proto.supportedCompressions)) - self.assertEquals(compressions2, + self.assertEqual(compressions2, ','.join(self.proto.supportedCompressions)) - self.assertEquals(languages1, ','.join(self.proto.supportedLanguages)) - self.assertEquals(languages2, ','.join(self.proto.supportedLanguages)) - self.assertEquals(buf, '\x00' * 5) + self.assertEqual(languages1, ','.join(self.proto.supportedLanguages)) + self.assertEqual(languages2, ','.join(self.proto.supportedLanguages)) + self.assertEqual(buf, '\x00' * 5) + + + def test_receiveKEXINITReply(self): + """ + Immediately after connecting, the transport expects a KEXINIT message + and does not reply to it. + """ + self.transport.clear() + self.proto.dispatchMessage( + transport.MSG_KEXINIT, self._A_KEXINIT_MESSAGE) + self.assertEqual(self.packets, []) + + + def test_sendKEXINITReply(self): + """ + When a KEXINIT message is received which is not a reply to an earlier + KEXINIT message which was sent, a KEXINIT reply is sent. + """ + self.finishKeyExchange(self.proto) + del self.packets[:] + + self.proto.dispatchMessage( + transport.MSG_KEXINIT, self._A_KEXINIT_MESSAGE) + self.assertEqual(len(self.packets), 1) + self.assertEqual(self.packets[0][0], transport.MSG_KEXINIT) + + + def test_sendKexInitTwiceFails(self): + """ + A new key exchange cannot be started while a key exchange is already in + progress. If an attempt is made to send a I{KEXINIT} message using + L{SSHTransportBase.sendKexInit} while a key exchange is in progress + causes that method to raise a L{RuntimeError}. + """ + self.assertRaises(RuntimeError, self.proto.sendKexInit) + + + def test_sendKexInitBlocksOthers(self): + """ + After L{SSHTransportBase.sendKexInit} has been called, messages types + other than the following are queued and not sent until after I{NEWKEYS} + is sent by L{SSHTransportBase._keySetup}. + + RFC 4253, section 7.1. + """ + # sendKexInit is called by connectionMade, which is called in setUp. So + # we're in the state already. + disallowedMessageTypes = [ + transport.MSG_SERVICE_REQUEST, + transport.MSG_KEXINIT, + ] + + # Drop all the bytes sent by setUp, they're not relevant to this test. + self.transport.clear() + + # Get rid of the sendPacket monkey patch, we are testing the behavior of + # sendPacket. + del self.proto.sendPacket + + for messageType in disallowedMessageTypes: + self.proto.sendPacket(messageType, 'foo') + self.assertEqual(self.transport.value(), "") + + self.finishKeyExchange(self.proto) + # Make the bytes written to the transport cleartext so it's easier to + # make an assertion about them. + self.proto.nextEncryptions = MockCipher() + + # Pseudo-deliver the peer's NEWKEYS message, which should flush the + # messages which were queued above. + self.proto._newKeys() + self.assertEqual(self.transport.value().count("foo"), 2) def test_sendDebug(self): @@ -571,7 +711,7 @@ string language """ self.proto.sendDebug("test", True, 'en') - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_DEBUG, "\x01\x00\x00\x00\x04test\x00\x00\x00\x02en")]) @@ -584,7 +724,7 @@ self.proto.dispatchMessage( transport.MSG_DEBUG, '\x01\x00\x00\x00\x04test\x00\x00\x00\x02en') - self.assertEquals(self.proto.debugs, [(True, 'test', 'en')]) + self.assertEqual(self.proto.debugs, [(True, 'test', 'en')]) def test_sendIgnore(self): @@ -593,7 +733,7 @@ string ignored data """ self.proto.sendIgnore("test") - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_IGNORE, '\x00\x00\x00\x04test')]) @@ -604,7 +744,7 @@ test_sendIgnore. """ self.proto.dispatchMessage(transport.MSG_IGNORE, 'test') - self.assertEquals(self.proto.ignoreds, ['test']) + self.assertEqual(self.proto.ignoreds, ['test']) def test_sendUnimplemented(self): @@ -613,7 +753,7 @@ uint32 sequence number """ self.proto.sendUnimplemented() - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_UNIMPLEMENTED, '\x00\x00\x00\x00')]) @@ -625,7 +765,7 @@ """ self.proto.dispatchMessage(transport.MSG_UNIMPLEMENTED, '\x00\x00\x00\xff') - self.assertEquals(self.proto.unimplementeds, [255]) + self.assertEqual(self.proto.unimplementeds, [255]) def test_sendDisconnect(self): @@ -640,7 +780,7 @@ disconnected[0] = True self.transport.loseConnection = stubLoseConnection self.proto.sendDisconnect(0xff, "test") - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_DISCONNECT, "\x00\x00\x00\xff\x00\x00\x00\x04test\x00\x00\x00\x00")]) @@ -658,7 +798,7 @@ self.transport.loseConnection = stubLoseConnection self.proto.dispatchMessage(transport.MSG_DISCONNECT, '\x00\x00\x00\xff\x00\x00\x00\x04test') - self.assertEquals(self.proto.errors, [(255, 'test')]) + self.assertEqual(self.proto.errors, [(255, 'test')]) self.assertTrue(disconnected[0]) @@ -673,7 +813,7 @@ self.proto.ssh_KEXINIT = stubKEXINIT self.proto.dataReceived(self.transport.value()) self.assertTrue(self.proto.gotVersion) - self.assertEquals(self.proto.ourVersionString, + self.assertEqual(self.proto.ourVersionString, self.proto.otherVersionString) self.assertTrue(kexInit[0]) @@ -685,10 +825,10 @@ """ service = MockService() self.proto.setService(service) - self.assertEquals(self.proto.service, service) + self.assertEqual(self.proto.service, service) self.assertTrue(service.started) self.proto.dispatchMessage(0xff, "test") - self.assertEquals(self.packets, [(0xff, "test")]) + self.assertEqual(self.packets, [(0xff, "test")]) service2 = MockService() self.proto.setService(service2) @@ -763,8 +903,8 @@ disconnected[0] = True self.transport.loseConnection = stubLoseConnection self.proto.loseConnection() - self.assertEquals(self.packets[0][0], transport.MSG_DISCONNECT) - self.assertEquals(self.packets[0][1][3], + self.assertEqual(self.packets[0][0], transport.MSG_DISCONNECT) + self.assertEqual(self.packets[0][1][3], chr(transport.DISCONNECT_CONNECTION_LOST)) @@ -782,8 +922,8 @@ for c in version + '\r\n': self.proto.dataReceived(c) self.assertTrue(disconnected[0]) - self.assertEquals(self.packets[0][0], transport.MSG_DISCONNECT) - self.assertEquals( + self.assertEqual(self.packets[0][0], transport.MSG_DISCONNECT) + self.assertEqual( self.packets[0][1][3], chr(transport.DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED)) testBad('SSH-1.5-OpenSSH') @@ -802,7 +942,7 @@ """ + proto.ourVersionString + "\r\n") [proto.dataReceived(c) for c in data] self.assertTrue(proto.gotVersion) - self.assertEquals(proto.otherVersionString, proto.ourVersionString) + self.assertEqual(proto.otherVersionString, proto.ourVersionString) def test_compatabilityVersion(self): @@ -814,7 +954,7 @@ proto.makeConnection(proto_helpers.StringTransport()) proto.dataReceived("SSH-1.99-OpenSSH\n") self.assertTrue(proto.gotVersion) - self.assertEquals(proto.otherVersionString, "SSH-1.99-OpenSSH") + self.assertEqual(proto.otherVersionString, "SSH-1.99-OpenSSH") def test_supportedVersionsAreAllowed(self): @@ -838,7 +978,7 @@ proto.supportedVersions = ("2.0", ) proto.makeConnection(proto_helpers.StringTransport()) proto.dataReceived("SSH-9.99-OpenSSH\n") - self.assertEquals("9.99", proto.gotUnsupportedVersion) + self.assertEqual("9.99", proto.gotUnsupportedVersion) def test_badPackets(self): @@ -849,10 +989,10 @@ def testBad(packet, error=transport.DISCONNECT_PROTOCOL_ERROR): self.packets = [] self.proto.buf = packet - self.assertEquals(self.proto.getPacket(), None) - self.assertEquals(len(self.packets), 1) - self.assertEquals(self.packets[0][0], transport.MSG_DISCONNECT) - self.assertEquals(self.packets[0][1][3], chr(error)) + self.assertEqual(self.proto.getPacket(), None) + self.assertEqual(len(self.packets), 1) + self.assertEqual(self.packets[0][0], transport.MSG_DISCONNECT) + self.assertEqual(self.packets[0][1][3], chr(error)) testBad('\xff' * 8) # big packet testBad('\x00\x00\x00\x05\x00BCDE') # length not modulo blocksize @@ -879,9 +1019,9 @@ """ seqnum = self.proto.incomingPacketSequence def checkUnimplemented(seqnum=seqnum): - self.assertEquals(self.packets[0][0], + self.assertEqual(self.packets[0][0], transport.MSG_UNIMPLEMENTED) - self.assertEquals(self.packets[0][1][3], chr(seqnum)) + self.assertEqual(self.packets[0][1][3], chr(seqnum)) self.proto.packets = [] seqnum += 1 @@ -907,7 +1047,7 @@ k1 = sha1('AB' + 'CD' + 'K' + self.proto.sessionID).digest() k2 = sha1('ABCD' + k1).digest() - self.assertEquals(self.proto._getKey('K', 'AB', 'CD'), k1 + k2) + self.assertEqual(self.proto._getKey('K', 'AB', 'CD'), k1 + k2) def test_multipleClasses(self): @@ -947,8 +1087,8 @@ """ if kind is None: kind = transport.DISCONNECT_PROTOCOL_ERROR - self.assertEquals(self.packets[-1][0], transport.MSG_DISCONNECT) - self.assertEquals(self.packets[-1][1][3], chr(kind)) + self.assertEqual(self.packets[-1][0], transport.MSG_DISCONNECT) + self.assertEqual(self.packets[-1][1][3], chr(kind)) def connectModifiedProtocol(self, protoModification, @@ -1054,19 +1194,19 @@ '\tnone,zlib\x00\x00\x00\tnone,zlib\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x99\x99\x99\x99\x99\x99\x99\x99' '\x99') - self.assertEquals(self.proto.kexAlg, + self.assertEqual(self.proto.kexAlg, 'diffie-hellman-group1-sha1') - self.assertEquals(self.proto.keyAlg, + self.assertEqual(self.proto.keyAlg, 'ssh-dss') - self.assertEquals(self.proto.outgoingCompressionType, + self.assertEqual(self.proto.outgoingCompressionType, 'none') - self.assertEquals(self.proto.incomingCompressionType, + self.assertEqual(self.proto.incomingCompressionType, 'none') ne = self.proto.nextEncryptions - self.assertEquals(ne.outCipType, 'aes128-ctr') - self.assertEquals(ne.inCipType, 'aes128-ctr') - self.assertEquals(ne.outMACType, 'hmac-md5') - self.assertEquals(ne.inMACType, 'hmac-md5') + self.assertEqual(ne.outCipType, 'aes128-ctr') + self.assertEqual(ne.inCipType, 'aes128-ctr') + self.assertEqual(ne.outMACType, 'hmac-md5') + self.assertEqual(ne.inMACType, 'hmac-md5') def test_ignoreGuessPacketKex(self): @@ -1099,12 +1239,12 @@ self.proto.ssh_KEX_DH_GEX_REQUEST_OLD('\x00\x00\x08\x00') self.assertFalse(self.proto.ignoreNextPacket) - self.assertEquals(self.packets, []) + self.assertEqual(self.packets, []) self.proto.ignoreNextPacket = True self.proto.ssh_KEX_DH_GEX_REQUEST('\x00\x00\x08\x00' * 3) self.assertFalse(self.proto.ignoreNextPacket) - self.assertEquals(self.packets, []) + self.assertEqual(self.packets, []) def test_ignoreGuessPacketKey(self): @@ -1133,12 +1273,12 @@ self.proto.ssh_KEX_DH_GEX_REQUEST_OLD('\x00\x00\x08\x00') self.assertFalse(self.proto.ignoreNextPacket) - self.assertEquals(self.packets, []) + self.assertEqual(self.packets, []) self.proto.ignoreNextPacket = True self.proto.ssh_KEX_DH_GEX_REQUEST('\x00\x00\x08\x00' * 3) self.assertFalse(self.proto.ignoreNextPacket) - self.assertEquals(self.packets, []) + self.assertEqual(self.packets, []) def test_KEXDH_INIT(self): @@ -1169,7 +1309,7 @@ signature = self.proto.factory.privateKeys['ssh-rsa'].sign( exchangeHash) - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_KEXDH_REPLY, common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob()) @@ -1188,12 +1328,12 @@ self.proto.supportedPublicKeys = ['ssh-rsa'] self.proto.dataReceived(self.transport.value()) self.proto.ssh_KEX_DH_GEX_REQUEST_OLD('\x00\x00\x04\x00') - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_KEX_DH_GEX_GROUP, common.MP(transport.DH_PRIME) + '\x00\x00\x00\x01\x02')]) - self.assertEquals(self.proto.g, 2) - self.assertEquals(self.proto.p, transport.DH_PRIME) + self.assertEqual(self.proto.g, 2) + self.assertEqual(self.proto.p, transport.DH_PRIME) def test_KEX_DH_GEX_REQUEST_OLD_badKexAlg(self): @@ -1219,12 +1359,12 @@ self.proto.dataReceived(self.transport.value()) self.proto.ssh_KEX_DH_GEX_REQUEST('\x00\x00\x04\x00\x00\x00\x08\x00' + '\x00\x00\x0c\x00') - self.assertEquals( + self.assertEqual( self.packets, [(transport.MSG_KEX_DH_GEX_GROUP, common.MP(transport.DH_PRIME) + '\x00\x00\x00\x01\x03')]) - self.assertEquals(self.proto.g, 3) - self.assertEquals(self.proto.p, transport.DH_PRIME) + self.assertEqual(self.proto.g, 3) + self.assertEqual(self.proto.p, transport.DH_PRIME) def test_KEX_DH_GEX_INIT_after_REQUEST(self): @@ -1250,7 +1390,7 @@ h.update(sharedSecret) exchangeHash = h.digest() self.proto.ssh_KEX_DH_GEX_INIT(common.MP(e)) - self.assertEquals( + self.assertEqual( self.packets[1], (transport.MSG_KEX_DH_GEX_REPLY, common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob()) + @@ -1281,7 +1421,7 @@ h.update(sharedSecret) exchangeHash = h.digest() self.proto.ssh_KEX_DH_GEX_INIT(common.MP(e)) - self.assertEquals( + self.assertEqual( self.packets[1:], [(transport.MSG_KEX_DH_GEX_REPLY, common.NS(self.proto.factory.publicKeys['ssh-rsa'].blob()) + @@ -1295,13 +1435,13 @@ Test that _keySetup sets up the next encryption keys. """ self.proto.nextEncryptions = MockCipher() - self.proto._keySetup('AB', 'CD') - self.assertEquals(self.proto.sessionID, 'CD') - self.proto._keySetup('AB', 'EF') - self.assertEquals(self.proto.sessionID, 'CD') - self.assertEquals(self.packets[-1], (transport.MSG_NEWKEYS, '')) + self.simulateKeyExchange('AB', 'CD') + self.assertEqual(self.proto.sessionID, 'CD') + self.simulateKeyExchange('AB', 'EF') + self.assertEqual(self.proto.sessionID, 'CD') + self.assertEqual(self.packets[-1], (transport.MSG_NEWKEYS, '')) newKeys = [self.proto._getKey(c, 'AB', 'EF') for c in 'ABCDEF'] - self.assertEquals( + self.assertEqual( self.proto.nextEncryptions.keys, (newKeys[1], newKeys[3], newKeys[0], newKeys[2], newKeys[5], newKeys[4])) @@ -1322,9 +1462,11 @@ self.assertIdentical(self.proto.outgoingCompression, None) self.assertIdentical(self.proto.incomingCompression, None) self.proto.outgoingCompressionType = 'zlib' + self.simulateKeyExchange('AB', 'CD') self.proto.ssh_NEWKEYS('') self.failIfIdentical(self.proto.outgoingCompression, None) self.proto.incomingCompressionType = 'zlib' + self.simulateKeyExchange('AB', 'EF') self.proto.ssh_NEWKEYS('') self.failIfIdentical(self.proto.incomingCompression, None) @@ -1335,9 +1477,9 @@ service. """ self.proto.ssh_SERVICE_REQUEST(common.NS('ssh-userauth')) - self.assertEquals(self.packets, [(transport.MSG_SERVICE_ACCEPT, + self.assertEqual(self.packets, [(transport.MSG_SERVICE_ACCEPT, common.NS('ssh-userauth'))]) - self.assertEquals(self.proto.service.name, 'MockService') + self.assertEqual(self.proto.service.name, 'MockService') def test_disconnectNEWKEYSData(self): @@ -1386,19 +1528,19 @@ '\tzlib,none\x00\x00\x00\tzlib,none\x00\x00\x00\x00\x00\x00' '\x00\x00\x00\x00\x00\x00\x00\x99\x99\x99\x99\x99\x99\x99\x99' '\x99') - self.assertEquals(self.proto.kexAlg, + self.assertEqual(self.proto.kexAlg, 'diffie-hellman-group-exchange-sha1') - self.assertEquals(self.proto.keyAlg, + self.assertEqual(self.proto.keyAlg, 'ssh-rsa') - self.assertEquals(self.proto.outgoingCompressionType, + self.assertEqual(self.proto.outgoingCompressionType, 'none') - self.assertEquals(self.proto.incomingCompressionType, + self.assertEqual(self.proto.incomingCompressionType, 'none') ne = self.proto.nextEncryptions - self.assertEquals(ne.outCipType, 'aes256-ctr') - self.assertEquals(ne.inCipType, 'aes256-ctr') - self.assertEquals(ne.outMACType, 'hmac-sha1') - self.assertEquals(ne.inMACType, 'hmac-sha1') + self.assertEqual(ne.outCipType, 'aes256-ctr') + self.assertEqual(ne.inCipType, 'aes256-ctr') + self.assertEqual(ne.outMACType, 'hmac-sha1') + self.assertEqual(ne.inMACType, 'hmac-sha1') def verifyHostKey(self, pubKey, fingerprint): @@ -1406,8 +1548,8 @@ Mock version of SSHClientTransport.verifyHostKey. """ self.calledVerifyHostKey = True - self.assertEquals(pubKey, self.blob) - self.assertEquals(fingerprint.replace(':', ''), + self.assertEqual(pubKey, self.blob) + self.assertEqual(fingerprint.replace(':', ''), md5(pubKey).hexdigest()) return defer.succeed(True) @@ -1441,7 +1583,7 @@ self.proto.supportedKeyExchanges = [ 'diffie-hellman-group-exchange-sha1'] self.proto.dataReceived(self.transport.value()) - self.assertEquals(self.packets, [(transport.MSG_KEX_DH_GEX_REQUEST_OLD, + self.assertEqual(self.packets, [(transport.MSG_KEX_DH_GEX_REQUEST_OLD, '\x00\x00\x08\x00')]) @@ -1451,8 +1593,8 @@ """ self.proto.supportedKeyExchanges = ['diffie-hellman-group1-sha1'] self.proto.dataReceived(self.transport.value()) - self.assertEquals(common.MP(self.proto.x)[5:], '\x99' * 64) - self.assertEquals(self.packets, + self.assertEqual(common.MP(self.proto.x)[5:], '\x99' * 64) + self.assertEqual(self.packets, [(transport.MSG_KEXDH_INIT, self.proto.e)]) @@ -1486,8 +1628,8 @@ def _cbTestKEXDH_REPLY(value): self.assertIdentical(value, None) - self.assertEquals(self.calledVerifyHostKey, True) - self.assertEquals(self.proto.sessionID, exchangeHash) + self.assertEqual(self.calledVerifyHostKey, True) + self.assertEqual(self.proto.sessionID, exchangeHash) signature = self.privObj.sign(exchangeHash) @@ -1507,12 +1649,12 @@ self.test_KEXINIT_groupexchange() self.proto.ssh_KEX_DH_GEX_GROUP( '\x00\x00\x00\x01\x0f\x00\x00\x00\x01\x02') - self.assertEquals(self.proto.p, 15) - self.assertEquals(self.proto.g, 2) - self.assertEquals(common.MP(self.proto.x)[5:], '\x99' * 40) - self.assertEquals(self.proto.e, + self.assertEqual(self.proto.p, 15) + self.assertEqual(self.proto.g, 2) + self.assertEqual(common.MP(self.proto.x)[5:], '\x99' * 40) + self.assertEqual(self.proto.e, common.MP(pow(2, self.proto.x, 15))) - self.assertEquals(self.packets[1:], [(transport.MSG_KEX_DH_GEX_INIT, + self.assertEqual(self.packets[1:], [(transport.MSG_KEX_DH_GEX_INIT, self.proto.e)]) @@ -1536,8 +1678,8 @@ def _cbTestKEX_DH_GEX_REPLY(value): self.assertIdentical(value, None) - self.assertEquals(self.calledVerifyHostKey, True) - self.assertEquals(self.proto.sessionID, exchangeHash) + self.assertEqual(self.calledVerifyHostKey, True) + self.assertEqual(self.proto.sessionID, exchangeHash) signature = self.privObj.sign(exchangeHash) @@ -1554,13 +1696,13 @@ Test that _keySetup sets up the next encryption keys. """ self.proto.nextEncryptions = MockCipher() - self.proto._keySetup('AB', 'CD') - self.assertEquals(self.proto.sessionID, 'CD') - self.proto._keySetup('AB', 'EF') - self.assertEquals(self.proto.sessionID, 'CD') - self.assertEquals(self.packets[-1], (transport.MSG_NEWKEYS, '')) + self.simulateKeyExchange('AB', 'CD') + self.assertEqual(self.proto.sessionID, 'CD') + self.simulateKeyExchange('AB', 'EF') + self.assertEqual(self.proto.sessionID, 'CD') + self.assertEqual(self.packets[-1], (transport.MSG_NEWKEYS, '')) newKeys = [self.proto._getKey(c, 'AB', 'EF') for c in 'ABCDEF'] - self.assertEquals(self.proto.nextEncryptions.keys, + self.assertEqual(self.proto.nextEncryptions.keys, (newKeys[0], newKeys[2], newKeys[1], newKeys[3], newKeys[4], newKeys[5])) @@ -1576,24 +1718,25 @@ secure[0] = True self.proto.connectionSecure = stubConnectionSecure - self.proto.nextEncryptions = transport.SSHCiphers('none', 'none', - 'none', 'none') - self.proto.ssh_NEWKEYS('') - - self.failIfIdentical(self.proto.currentEncryptions, - self.proto.nextEncryptions) + self.proto.nextEncryptions = transport.SSHCiphers( + 'none', 'none', 'none', 'none') + self.simulateKeyExchange('AB', 'CD') + self.assertNotIdentical( + self.proto.currentEncryptions, self.proto.nextEncryptions) self.proto.nextEncryptions = MockCipher() - self.proto._keySetup('AB', 'EF') + self.proto.ssh_NEWKEYS('') self.assertIdentical(self.proto.outgoingCompression, None) self.assertIdentical(self.proto.incomingCompression, None) self.assertIdentical(self.proto.currentEncryptions, self.proto.nextEncryptions) self.assertTrue(secure[0]) self.proto.outgoingCompressionType = 'zlib' + self.simulateKeyExchange('AB', 'GH') self.proto.ssh_NEWKEYS('') self.failIfIdentical(self.proto.outgoingCompression, None) self.proto.incomingCompressionType = 'zlib' + self.simulateKeyExchange('AB', 'IJ') self.proto.ssh_NEWKEYS('') self.failIfIdentical(self.proto.incomingCompression, None) @@ -1612,7 +1755,7 @@ Test that requesting a service sends a SERVICE_REQUEST packet. """ self.proto.requestService(MockService()) - self.assertEquals(self.packets, [(transport.MSG_SERVICE_REQUEST, + self.assertEqual(self.packets, [(transport.MSG_SERVICE_REQUEST, '\x00\x00\x00\x0bMockService')]) @@ -1661,7 +1804,7 @@ skip = "cannot run w/o PyCrypto" if pyasn1 is None: - skip = "cannot run w/o PyASN1" + skip = "Cannot run without PyASN1" def test_init(self): @@ -1669,10 +1812,10 @@ Test that the initializer sets up the SSHCiphers object. """ ciphers = transport.SSHCiphers('A', 'B', 'C', 'D') - self.assertEquals(ciphers.outCipType, 'A') - self.assertEquals(ciphers.inCipType, 'B') - self.assertEquals(ciphers.outMACType, 'C') - self.assertEquals(ciphers.inMACType, 'D') + self.assertEqual(ciphers.outCipType, 'A') + self.assertEqual(ciphers.inCipType, 'B') + self.assertEqual(ciphers.outMACType, 'C') + self.assertEqual(ciphers.inMACType, 'D') def test_getCipher(self): @@ -1700,12 +1843,12 @@ if macName == 'none': self.assertIdentical(mac, None) else: - self.assertEquals(mod[0], mac) - self.assertEquals(mod[1], + self.assertEqual(mod[0], mac) + self.assertEqual(mod[1], Crypto.Cipher.XOR.new('\x36').encrypt(key)) - self.assertEquals(mod[2], + self.assertEqual(mod[2], Crypto.Cipher.XOR.new('\x5c').encrypt(key)) - self.assertEquals(mod[3], len(mod[0]().digest())) + self.assertEqual(mod[3], len(mod[0]().digest())) def test_setKeysCiphers(self): @@ -1721,16 +1864,16 @@ bs = cip.block_size encCipher.setKeys(key, key, '', '', '', '') decCipher.setKeys('', '', key, key, '', '') - self.assertEquals(encCipher.encBlockSize, bs) - self.assertEquals(decCipher.decBlockSize, bs) + self.assertEqual(encCipher.encBlockSize, bs) + self.assertEqual(decCipher.decBlockSize, bs) enc = cip.encrypt(key[:bs]) enc2 = cip.encrypt(key[:bs]) if counter: self.failIfEquals(enc, enc2) - self.assertEquals(encCipher.encrypt(key[:bs]), enc) - self.assertEquals(encCipher.encrypt(key[:bs]), enc2) - self.assertEquals(decCipher.decrypt(enc), key[:bs]) - self.assertEquals(decCipher.decrypt(enc2), key[:bs]) + self.assertEqual(encCipher.encrypt(key[:bs]), enc) + self.assertEqual(encCipher.encrypt(key[:bs]), enc2) + self.assertEqual(decCipher.decrypt(enc), key[:bs]) + self.assertEqual(decCipher.decrypt(enc2), key[:bs]) def test_setKeysMACs(self): @@ -1747,7 +1890,7 @@ ds = mod().digest_size else: ds = 0 - self.assertEquals(inMac.verifyDigestSize, ds) + self.assertEqual(inMac.verifyDigestSize, ds) if mod: mod, i, o, ds = outMac._getMAC(macName, key) seqid = 0 @@ -1757,7 +1900,7 @@ mac = mod(o + mod(i + packet).digest()).digest() else: mac = '' - self.assertEquals(outMac.makeMAC(seqid, data), mac) + self.assertEqual(outMac.makeMAC(seqid, data), mac) self.assertTrue(inMac.verify(seqid, data, mac)) @@ -1770,7 +1913,7 @@ skip = "cannot run w/o PyCrypto" if pyasn1 is None: - skip = "cannot run w/o PyASN1" + skip = "Cannot run without PyASN1" def test_init(self): @@ -1778,8 +1921,8 @@ Test that the counter is initialized correctly. """ counter = transport._Counter('\x00' * 8 + '\xff' * 8, 8) - self.assertEquals(counter.blockSize, 8) - self.assertEquals(counter.count.tostring(), '\x00' * 8) + self.assertEqual(counter.blockSize, 8) + self.assertEqual(counter.count.tostring(), '\x00' * 8) def test_count(self): @@ -1787,11 +1930,11 @@ Test that the counter counts incrementally and wraps at the top. """ counter = transport._Counter('\x00', 1) - self.assertEquals(counter(), '\x01') - self.assertEquals(counter(), '\x02') + self.assertEqual(counter(), '\x01') + self.assertEqual(counter(), '\x02') [counter() for i in range(252)] - self.assertEquals(counter(), '\xff') - self.assertEquals(counter(), '\x00') + self.assertEqual(counter(), '\xff') + self.assertEqual(counter(), '\x00') @@ -1803,7 +1946,7 @@ skip = "cannot run w/o PyCrypto" if pyasn1 is None: - skip = "cannot run w/o PyASN1" + skip = "Cannot run without PyASN1" def _runClientServer(self, mod): @@ -1835,8 +1978,8 @@ server.supportedMACs[0], server.supportedKeyExchanges[0], server.supportedCompressions[0]]) - self.assertEquals(client.errors, []) - self.assertEquals(server.errors, [( + self.assertEqual(client.errors, []) + self.assertEqual(server.errors, [( transport.DISCONNECT_CONNECTION_LOST, "user closed connection")]) if server.supportedCiphers[0] == 'none': @@ -1926,7 +2069,7 @@ # The number of bytes requested will be the value of each byte # we return. return chr(bytes) * bytes - self.assertEquals( + self.assertEqual( transport._getRandomNumber(random, 32), 4 << 24 | 4 << 16 | 4 << 8 | 4) @@ -1950,7 +2093,7 @@ results = [chr(0), chr(1), chr(127)] def random(bytes): return results.pop(0) * bytes - self.assertEquals( + self.assertEqual( transport._generateX(random, 8), 127) @@ -1965,7 +2108,7 @@ results = [chr(255), chr(64)] def random(bytes): return results.pop(0) * bytes - self.assertEquals( + self.assertEqual( transport._generateX(random, 8), 64) @@ -1985,7 +2128,7 @@ skip = "cannot run w/o PyCrypto" if pyasn1 is None: - skip = "cannot run w/o PyASN1" + skip = "Cannot run without PyASN1" def test_getPublicKeysWarning(self): @@ -2000,7 +2143,7 @@ "a mapping from strings to Key objects instead." % (qual(MockOldFactoryPublicKeys),), factory.__file__, sshFactory.startFactory) - self.assertEquals(sshFactory.publicKeys, MockFactory().getPublicKeys()) + self.assertEqual(sshFactory.publicKeys, MockFactory().getPublicKeys()) def test_getPrivateKeysWarning(self): @@ -2015,7 +2158,7 @@ " a mapping from strings to Key objects instead." % (qual(MockOldFactoryPrivateKeys),), factory.__file__, sshFactory.startFactory) - self.assertEquals(sshFactory.privateKeys, + self.assertEqual(sshFactory.privateKeys, MockFactory().getPrivateKeys()) @@ -2032,7 +2175,7 @@ "a mapping from strings to Key objects instead." % (qual(MockOldFactoryPublicKeys),), factory.__file__, sshFactory.startFactory) - self.assertEquals(sshFactory.publicKeys, MockFactory().getPublicKeys()) + self.assertEqual(sshFactory.publicKeys, MockFactory().getPublicKeys()) def test_privateKeysWarning(self): @@ -2049,5 +2192,5 @@ " a mapping from strings to Key objects instead." % (qual(MockOldFactoryPrivateKeys),), factory.__file__, sshFactory.startFactory) - self.assertEquals(sshFactory.privateKeys, + self.assertEqual(sshFactory.privateKeys, MockFactory().getPrivateKeys()) diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_userauth.py twisted-conch-12.1.0/twisted/conch/test/test_userauth.py --- twisted-conch-10.2.0/twisted/conch/test/test_userauth.py 2010-02-11 21:06:03.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_userauth.py 2011-08-26 14:19:19.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.conch.test.test_userauth -*- -# Copyright (c) 2007-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -306,7 +306,7 @@ """ Check that the authentication has failed. """ - self.assertEquals(self.authServer.transport.packets[-1], + self.assertEqual(self.authServer.transport.packets[-1], (userauth.MSG_USERAUTH_FAILURE, NS('keyboard-interactive,password,publickey') + '\x00')) @@ -353,7 +353,7 @@ packet = NS('foo') + NS('none') + NS('password') + chr(0) + NS('bar') self.authServer.clock = task.Clock() d = self.authServer.ssh_USERAUTH_REQUEST(packet) - self.assertEquals(self.authServer.transport.packets, []) + self.assertEqual(self.authServer.transport.packets, []) self.authServer.clock.advance(2) return d.addCallback(self._checkFailed) @@ -372,7 +372,7 @@ packet += NS(signature) d = self.authServer.ssh_USERAUTH_REQUEST(packet) def check(ignored): - self.assertEquals(self.authServer.transport.packets, + self.assertEqual(self.authServer.transport.packets, [(userauth.MSG_USERAUTH_SUCCESS, '')]) return d.addCallback(check) @@ -413,7 +413,7 @@ + NS('ssh-rsa') + NS(blob)) d = self.authServer.ssh_USERAUTH_REQUEST(packet) def check(ignored): - self.assertEquals(self.authServer.transport.packets, + self.assertEqual(self.authServer.transport.packets, [(userauth.MSG_USERAUTH_PK_OK, NS('ssh-rsa') + NS(blob))]) return d.addCallback(check) @@ -454,7 +454,7 @@ d = self.authServer.ssh_USERAUTH_REQUEST(packet) self.authServer.ssh_USERAUTH_INFO_RESPONSE(response) def check(ignored): - self.assertEquals(self.authServer.transport.packets, + self.assertEqual(self.authServer.transport.packets, [(userauth.MSG_USERAUTH_INFO_REQUEST, (NS('') + NS('') + NS('') + '\x00\x00\x00\x02' + NS('Name: ') + '\x01' + NS('Password: ') + '\x00')), @@ -473,7 +473,7 @@ d = self.authServer.ssh_USERAUTH_REQUEST(packet) self.authServer.ssh_USERAUTH_INFO_RESPONSE(response) def check(ignored): - self.assertEquals(self.authServer.transport.packets[0], + self.assertEqual(self.authServer.transport.packets[0], (userauth.MSG_USERAUTH_INFO_REQUEST, (NS('') + NS('') + NS('') + '\x00\x00\x00\x02' + NS('Name: ') + '\x01' + NS('Password: ') + '\x00'))) @@ -515,9 +515,9 @@ + NS('') + NS('')) self.authServer.ssh_USERAUTH_REQUEST(packet) self.authServer.ssh_USERAUTH_REQUEST(packet) - self.assertEquals(self.authServer.transport.packets[-1][0], + self.assertEqual(self.authServer.transport.packets[-1][0], transport.MSG_DISCONNECT) - self.assertEquals(self.authServer.transport.packets[-1][1][3], + self.assertEqual(self.authServer.transport.packets[-1][1][3], chr(transport.DISCONNECT_PROTOCOL_ERROR)) @@ -536,7 +536,7 @@ server.serviceStarted() server.serviceStopped() server.supportedAuthentications.sort() # give a consistent order - self.assertEquals(server.supportedAuthentications, + self.assertEqual(server.supportedAuthentications, ['keyboard-interactive', 'password', 'publickey']) @@ -603,7 +603,7 @@ clearAuthServer.transport.isEncrypted = lambda x: False clearAuthServer.serviceStarted() clearAuthServer.serviceStopped() - self.assertEquals(clearAuthServer.supportedAuthentications, + self.assertEqual(clearAuthServer.supportedAuthentications, ['publickey']) # only encrypt incoming (the direction the password is sent) @@ -612,7 +612,7 @@ halfAuthServer.transport.isEncrypted = lambda x: x == 'in' halfAuthServer.serviceStarted() halfAuthServer.serviceStopped() - self.assertEquals(clearAuthServer.supportedAuthentications, + self.assertEqual(clearAuthServer.supportedAuthentications, ['publickey']) @@ -626,7 +626,7 @@ timeoutAuthServer.serviceStarted() timeoutAuthServer.clock.advance(11 * 60 * 60) timeoutAuthServer.serviceStopped() - self.assertEquals(timeoutAuthServer.transport.packets, + self.assertEqual(timeoutAuthServer.transport.packets, [(transport.MSG_DISCONNECT, '\x00' * 3 + chr(transport.DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE) + @@ -644,7 +644,7 @@ timeoutAuthServer.serviceStarted() timeoutAuthServer.serviceStopped() timeoutAuthServer.clock.advance(11 * 60 * 60) - self.assertEquals(timeoutAuthServer.transport.packets, []) + self.assertEqual(timeoutAuthServer.transport.packets, []) self.assertFalse(timeoutAuthServer.transport.lostConnection) @@ -659,7 +659,7 @@ d = self.authServer.ssh_USERAUTH_REQUEST(packet) self.authServer.clock.advance(2) def check(ignored): - self.assertEquals(self.authServer.transport.packets[-1], + self.assertEqual(self.authServer.transport.packets[-1], (transport.MSG_DISCONNECT, '\x00' * 3 + chr(transport.DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE) + @@ -743,9 +743,9 @@ """ Test that client is initialized properly. """ - self.assertEquals(self.authClient.user, 'foo') - self.assertEquals(self.authClient.instance.name, 'nancy') - self.assertEquals(self.authClient.transport.packets, + self.assertEqual(self.authClient.user, 'foo') + self.assertEqual(self.authClient.instance.name, 'nancy') + self.assertEqual(self.authClient.transport.packets, [(userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('none'))]) @@ -759,7 +759,7 @@ instance[0] = service self.authClient.transport.setService = stubSetService self.authClient.ssh_USERAUTH_SUCCESS('') - self.assertEquals(instance[0], self.authClient.instance) + self.assertEqual(instance[0], self.authClient.instance) def test_publickey(self): @@ -767,7 +767,7 @@ Test that the client can authenticate with a public key. """ self.authClient.ssh_USERAUTH_FAILURE(NS('publickey') + '\x00') - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('publickey') + '\x00' + NS('ssh-dss') + NS(keys.Key.fromString( @@ -775,19 +775,19 @@ # that key isn't good self.authClient.ssh_USERAUTH_FAILURE(NS('publickey') + '\x00') blob = NS(keys.Key.fromString(keydata.publicRSA_openssh).blob()) - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, (NS('foo') + NS('nancy') + NS('publickey') + '\x00'+ NS('ssh-rsa') + blob))) self.authClient.ssh_USERAUTH_PK_OK(NS('ssh-rsa') + NS(keys.Key.fromString(keydata.publicRSA_openssh).blob())) sigData = (NS(self.authClient.transport.sessionID) + chr(userauth.MSG_USERAUTH_REQUEST) + NS('foo') - + NS('nancy') + NS('publickey') + '\xff' + NS('ssh-rsa') + + NS('nancy') + NS('publickey') + '\x01' + NS('ssh-rsa') + blob) obj = keys.Key.fromString(keydata.privateRSA_openssh) - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') - + NS('publickey') + '\xff' + NS('ssh-rsa') + blob + + NS('publickey') + '\x01' + NS('ssh-rsa') + blob + NS(obj.sign(sigData)))) @@ -806,7 +806,7 @@ authClient.tryAuth('publickey') authClient.transport.packets = [] self.assertIdentical(authClient.ssh_USERAUTH_PK_OK(''), None) - self.assertEquals(authClient.transport.packets, [ + self.assertEqual(authClient.transport.packets, [ (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('none'))]) @@ -826,7 +826,7 @@ "SSHUserAuthClient.getPublicKey() is deprecated since " "Twisted 9.0. Return a keys.Key() instead.", userauth.__file__, oldAuth.tryAuth, 'publickey') - self.assertEquals(oldAuth.transport.packets, [ + self.assertEqual(oldAuth.transport.packets, [ (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('publickey') + '\x00' + NS('ssh-rsa') + NS(keys.Key.fromString(keydata.publicRSA_openssh).blob()))]) @@ -845,7 +845,7 @@ "Return a keys.Key() instead.", userauth.__file__, oldAuth.signData, None, 'data') def _checkSignedData(sig): - self.assertEquals(sig, + self.assertEqual(sig, keys.Key.fromString(keydata.privateRSA_openssh).sign( 'data')) d.addCallback(_checkSignedData) @@ -869,11 +869,11 @@ includes changing the password. """ self.authClient.ssh_USERAUTH_FAILURE(NS('password') + '\x00') - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('password') + '\x00' + NS('foo'))) self.authClient.ssh_USERAUTH_PK_OK(NS('') + NS('')) - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('password') + '\xff' + NS('foo') * 2)) @@ -893,12 +893,12 @@ """ self.authClient.ssh_USERAUTH_FAILURE(NS('keyboard-interactive') + '\x00') - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('keyboard-interactive') + NS('')*2)) self.authClient.ssh_USERAUTH_PK_OK(NS('')*3 + '\x00\x00\x00\x02' + NS('Name: ') + '\xff' + NS('Password: ') + '\x00') - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_INFO_RESPONSE, '\x00\x00\x00\x02' + NS('foo')*2)) @@ -912,7 +912,7 @@ self.authClient.lastAuth = 'unknown' self.authClient.transport.packets = [] self.authClient.ssh_USERAUTH_PK_OK('') - self.assertEquals(self.authClient.transport.packets, + self.assertEqual(self.authClient.transport.packets, [(userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('none'))]) @@ -936,12 +936,12 @@ self.authClient.ssh_USERAUTH_FAILURE(NS('anothermethod,password') + '\x00') # should send password packet - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('password') + '\x00' + NS('foo'))) self.authClient.ssh_USERAUTH_FAILURE( NS('firstmethod,anothermethod,password') + '\xff') - self.assertEquals(self.authClient.transport.packets[-2:], + self.assertEqual(self.authClient.transport.packets[-2:], [(255, 'here is data'), (254, 'other data')]) @@ -953,7 +953,7 @@ """ self.authClient.ssh_USERAUTH_FAILURE(NS('password') + '\x00') self.authClient.ssh_USERAUTH_FAILURE(NS('password') + '\xff') - self.assertEquals(self.authClient.transport.packets[-1], + self.assertEqual(self.authClient.transport.packets[-1], (transport.MSG_DISCONNECT, '\x00\x00\x00\x0e' + NS('no more authentication methods available') + '\x00\x00\x00\x00')) @@ -966,7 +966,7 @@ """ self.authClient.transport.packets = [] self.authClient._ebAuth(None) - self.assertEquals(self.authClient.transport.packets, + self.assertEqual(self.authClient.transport.packets, [(userauth.MSG_USERAUTH_REQUEST, NS('foo') + NS('nancy') + NS('none'))]) @@ -1058,5 +1058,5 @@ client.serviceStarted() def check(ignored): - self.assertEquals(server.transport.service.name, 'TestService') + self.assertEqual(server.transport.service.name, 'TestService') return d.addCallback(check) diff -Nru twisted-conch-10.2.0/twisted/conch/test/test_window.py twisted-conch-12.1.0/twisted/conch/test/test_window.py --- twisted-conch-10.2.0/twisted/conch/test/test_window.py 2007-01-22 22:01:11.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/test/test_window.py 2011-05-15 14:25:06.000000000 +0000 @@ -5,7 +5,7 @@ from twisted.trial.unittest import TestCase -from twisted.conch.insults.window import TopWindow +from twisted.conch.insults.window import TopWindow, ScrolledArea, TextOutput class TopWindowTests(TestCase): @@ -47,3 +47,21 @@ root.repaint() self.assertEqual(len(paints), 1) self.assertEqual(len(scheduled), 1) + + + +class ScrolledAreaTests(TestCase): + """ + Tests for L{ScrolledArea}, a widget which creates a viewport containing + another widget and can reposition that viewport using scrollbars. + """ + def test_parent(self): + """ + The parent of the widget passed to L{ScrolledArea} is set to a new + L{Viewport} created by the L{ScrolledArea} which itself has the + L{ScrolledArea} instance as its parent. + """ + widget = TextOutput() + scrolled = ScrolledArea(widget) + self.assertIdentical(widget.parent, scrolled._viewport) + self.assertIdentical(scrolled._viewport.parent, scrolled) diff -Nru twisted-conch-10.2.0/twisted/conch/ttymodes.py twisted-conch-12.1.0/twisted/conch/ttymodes.py --- twisted-conch-10.2.0/twisted/conch/ttymodes.py 2004-08-25 08:36:30.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ttymodes.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/ui/ansi.py twisted-conch-12.1.0/twisted/conch/ui/ansi.py --- twisted-conch-10.2.0/twisted/conch/ui/ansi.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ui/ansi.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/ui/__init__.py twisted-conch-12.1.0/twisted/conch/ui/__init__.py --- twisted-conch-10.2.0/twisted/conch/ui/__init__.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ui/__init__.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/ui/tkvt100.py twisted-conch-12.1.0/twisted/conch/ui/tkvt100.py --- twisted-conch-10.2.0/twisted/conch/ui/tkvt100.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/ui/tkvt100.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-conch-10.2.0/twisted/conch/unix.py twisted-conch-12.1.0/twisted/conch/unix.py --- twisted-conch-10.2.0/twisted/conch/unix.py 2007-03-11 19:38:35.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/unix.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.cred import portal diff -Nru twisted-conch-10.2.0/twisted/conch/_version.py twisted-conch-12.1.0/twisted/conch/_version.py --- twisted-conch-10.2.0/twisted/conch/_version.py 2010-11-30 02:27:23.000000000 +0000 +++ twisted-conch-12.1.0/twisted/conch/_version.py 2012-06-02 07:04:01.000000000 +0000 @@ -1,3 +1,3 @@ # This is an auto-generated file. Do not edit it. from twisted.python import versions -version = versions.Version('twisted.conch', 10, 2, 0) +version = versions.Version('twisted.conch', 12, 1, 0) diff -Nru twisted-conch-10.2.0/twisted/plugins/twisted_conch.py twisted-conch-12.1.0/twisted/plugins/twisted_conch.py --- twisted-conch-10.2.0/twisted/plugins/twisted_conch.py 2008-04-08 15:53:14.000000000 +0000 +++ twisted-conch-12.1.0/twisted/plugins/twisted_conch.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.application.service import ServiceMaker