Skip to content

Commit

Permalink
Merge pull request twisted#557 from twisted/8855-rodrigc-ckeygen-py3
Browse files Browse the repository at this point in the history
Author: rodrigc
Reviewer: einarfd
Fixes: twisted#8855

Port ckeygen to Python 3
  • Loading branch information
rodrigc authored Oct 20, 2016
2 parents c2631e2 + 7810779 commit fdf4270
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 24 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ matrix:
# twistedchecker job was introduce as an experimental job.
# Once it is stable we can enforce it
- env: TOXENV=txchecker-travis
- osx_image: xcode7.1


addons:
Expand Down
8 changes: 6 additions & 2 deletions src/twisted/conch/scripts/ckeygen.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from twisted.conch.ssh import keys
from twisted.python import failure, filepath, log, usage
from twisted.python.compat import raw_input, _PY3



Expand Down Expand Up @@ -184,7 +185,7 @@ def changePassPhrase(options):
except (keys.EncryptedKeyError, keys.BadKeyError) as e:
sys.exit('Could not change passphrase: %s' % (e,))

with open(options['filename'], 'w') as fd:
with open(options['filename'], 'wb') as fd:
fd.write(newkeydata)

print('Your identification has been saved with the new passphrase.')
Expand All @@ -202,7 +203,10 @@ def displayPublicKey(options):
options['pass'] = getpass.getpass('Enter passphrase: ')
key = keys.Key.fromFile(
options['filename'], passphrase = options['pass'])
print(key.public().toString('openssh'))
displayKey = key.public().toString('openssh')
if _PY3:
displayKey = displayKey.decode("ascii")
print(displayKey)



Expand Down
10 changes: 8 additions & 2 deletions src/twisted/conch/ssh/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
from twisted.conch.ssh.common import int_from_bytes, int_to_bytes
from twisted.python import randbytes
from twisted.python.compat import (
iterbytes, long, izip, nativeString, _PY3,
iterbytes, long, izip, nativeString, unicode, _PY3,
_b64decodebytes as decodebytes, _b64encodebytes as encodebytes)
from twisted.python.constants import NamedConstant, Names
from twisted.python.deprecate import deprecated, getDeprecationWarningString
Expand Down Expand Up @@ -144,6 +144,10 @@ def fromString(cls, data, type=None, passphrase=None):
@rtype: L{Key}
@return: The loaded key.
"""
if isinstance(data, unicode):
data = data.encode("utf-8")
if isinstance(passphrase, unicode):
passphrase = passphrase.encode("utf-8")
if type is None:
type = cls._guessStringType(data)
if type is None:
Expand Down Expand Up @@ -1024,10 +1028,12 @@ def toString(self, type, extra=None):
is not part of the key itself. For public OpenSSH keys, this is
a comment. For private OpenSSH keys, this is a passphrase to
encrypt with.
@type extra: L{bytes} or L{None}
@type extra: L{bytes} or L{unicode} or L{None}
@rtype: L{bytes}
"""
if isinstance(extra, unicode):
extra = extra.encode("utf-8")
method = getattr(self, '_toString_%s' % (type.upper(),), None)
if method is None:
raise BadKeyError('unknown key type: %s' % (type,))
Expand Down
56 changes: 38 additions & 18 deletions src/twisted/conch/test/test_ckeygen.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
Tests for L{twisted.conch.scripts.ckeygen}.
"""

import __builtin__
import getpass
import sys
from StringIO import StringIO

from io import BytesIO, StringIO

from twisted.python.compat import unicode, _PY3
from twisted.python.reflect import requireModule

if requireModule('cryptography') and requireModule('pyasn1'):
Expand Down Expand Up @@ -41,7 +42,7 @@ def makeGetpass(*passphrases):
passphrases = iter(passphrases)

def fakeGetpass(_):
return passphrases.next()
return next(passphrases)

return fakeGetpass

Expand All @@ -53,10 +54,12 @@ class KeyGenTests(TestCase):
"""
def setUp(self):
"""
Patch C{sys.stdout} with a L{StringIO} instance to tests can make
assertions about what's printed.
Patch C{sys.stdout} so tests can make assertions about what's printed.
"""
self.stdout = StringIO()
if _PY3:
self.stdout = StringIO()
else:
self.stdout = BytesIO()
self.patch(sys, 'stdout', self.stdout)


Expand Down Expand Up @@ -231,7 +234,8 @@ def test_saveKeyNoFilename(self):
base.makedirs()
keyPath = base.child('custom_key').path

self.patch(__builtin__, 'raw_input', lambda _: keyPath)
import twisted.conch.scripts.ckeygen
self.patch(twisted.conch.scripts.ckeygen, 'raw_input', lambda _: keyPath)
key = Key.fromString(privateRSA_openssh)
_saveKey(key, {'filename': None, 'no-passphrase': True,
'format': 'md5-hex'})
Expand All @@ -250,8 +254,11 @@ def test_displayPublicKey(self):
pubKey = Key.fromString(publicRSA_openssh)
FilePath(filename).setContent(privateRSA_openssh)
displayPublicKey({'filename': filename})
displayed = self.stdout.getvalue().strip('\n')
if isinstance(displayed, unicode):
displayed = displayed.encode("ascii")
self.assertEqual(
self.stdout.getvalue().strip('\n'),
displayed,
pubKey.toString('openssh'))


Expand All @@ -264,8 +271,11 @@ def test_displayPublicKeyEncrypted(self):
pubKey = Key.fromString(publicRSA_openssh)
FilePath(filename).setContent(privateRSA_openssh_encrypted)
displayPublicKey({'filename': filename, 'pass': 'encrypted'})
displayed = self.stdout.getvalue().strip('\n')
if isinstance(displayed, unicode):
displayed = displayed.encode("ascii")
self.assertEqual(
self.stdout.getvalue().strip('\n'),
displayed,
pubKey.toString('openssh'))


Expand All @@ -279,8 +289,11 @@ def test_displayPublicKeyEncryptedPassphrasePrompt(self):
FilePath(filename).setContent(privateRSA_openssh_encrypted)
self.patch(getpass, 'getpass', lambda x: 'encrypted')
displayPublicKey({'filename': filename})
displayed = self.stdout.getvalue().strip('\n')
if isinstance(displayed, unicode):
displayed = displayed.encode("ascii")
self.assertEqual(
self.stdout.getvalue().strip('\n'),
displayed,
pubKey.toString('openssh'))


Expand Down Expand Up @@ -392,13 +405,16 @@ def test_changePassphraseBadKey(self):
key.
"""
filename = self.mktemp()
FilePath(filename).setContent('foobar')
FilePath(filename).setContent(b'foobar')
error = self.assertRaises(
SystemExit, changePassPhrase, {'filename': filename})
self.assertEqual(
"Could not change passphrase: cannot guess the type of 'foobar'",
str(error))
self.assertEqual('foobar', FilePath(filename).getContent())

if _PY3:
expected = "Could not change passphrase: cannot guess the type of b'foobar'"
else:
expected = "Could not change passphrase: cannot guess the type of 'foobar'"
self.assertEqual(expected, str(error))
self.assertEqual(b'foobar', FilePath(filename).getContent())


def test_changePassphraseCreateError(self):
Expand Down Expand Up @@ -442,9 +458,13 @@ def toString(*args, **kwargs):
SystemExit, changePassPhrase,
{'filename': filename, 'newpass': 'newencrypt'})

self.assertEqual(
"Could not change passphrase: "
"cannot guess the type of ''", str(error))
if _PY3:
expected = (
"Could not change passphrase: cannot guess the type of b''")
else:
expected = (
"Could not change passphrase: cannot guess the type of ''")
self.assertEqual(expected, str(error))

self.assertEqual(privateRSA_openssh, FilePath(filename).getContent())

Expand Down
1 change: 1 addition & 0 deletions src/twisted/conch/topfiles/8855.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ckeygen has been ported to Python 3
3 changes: 1 addition & 2 deletions src/twisted/python/_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,14 @@

# Scripts provided by Twisted on Python 2 and 3.
_CONSOLE_SCRIPTS = [
"ckeygen = twisted.conch.scripts.ckeygen:run",
"trial = twisted.scripts.trial:run",
"twist = twisted.application.twist._twist:Twist.main",
"twistd = twisted.scripts.twistd:run",
]
# Scripts provided by Twisted on Python 2 only.
_CONSOLE_SCRIPTS_PY2 = [
"cftp = twisted.conch.scripts.cftp:run",
"ckeygen = twisted.conch.scripts.ckeygen:run",
"conch = twisted.conch.scripts.conch:run",
"mailmail = twisted.mail.scripts.mailmail:run",
"pyhtmlizer = twisted.scripts.htmlizer:run",
Expand Down Expand Up @@ -361,7 +361,6 @@ def _checkCPython(sys=sys, platform=platform):
"twisted.conch.client.connect",
"twisted.conch.client.direct",
"twisted.conch.test.test_cftp",
"twisted.conch.test.test_ckeygen",
"twisted.conch.test.test_conch",
"twisted.conch.test.test_manhole",
"twisted.conch.ui.__init__",
Expand Down

0 comments on commit fdf4270

Please sign in to comment.