Flake8 fixes (#35)

* Apply Flake8 also on `setup.py`

modified:   tox.ini

* Fix W605 - invalid escape syntax

modified:   packages/setup.py
modified:   tox.ini

* Update comment about Flake8: W504

W503 and W504 are mutual exclusive - so we have to keep one of them.

modified:   tox.ini

* Fix F841 - variable assigned but never used

modified:   ssh-audit.py
modified:   tox.ini

* Fix E741 - ambiguous variable name 'l'

modified:   ssh-audit.py
modified:   tox.ini

* Fix E712 - comparison to False should be 'if cond is False'

... and not 'if conf == False'.

modified:   ssh-audit.py
modified:   tox.ini

* Fix E711 - comparison to None should be 'if cond is not None'

... and not 'if cond != None'.

modified:   ssh-audit.py
modified:   tox.ini

* Fix E305 - expected 2 blank lines

... after class or function definition, found 1.

modified:   ssh-audit.py
modified:   tox.ini

* Fix E303 - too many blank lines

modified:   ssh-audit.py
modified:   tox.ini

* Fix E303 - too many blank lines

modified:   ssh-audit.py
modified:   tox.ini

* Fix E301 - expected 1 blank line, found 0

No code change necessary, probably fixed by another commit.

modified:   tox.ini

* Fix E265 - block comment should start with '# '

There is lots of commented out code, which usually should be just
deleted.

I will keep it for now, as I am not yet very familiar with the code
base.

modified:   ssh-audit.py
modified:   tox.ini

* Fix E261 - at least two spaces before inline comment

modified:   ssh-audit.py
modified:   tox.ini

* Fix E251 - unexpected spaces around keyword / parameter equals

modified:   packages/setup.py
modified:   tox.ini

* Fix E231 - missing whitespace after ','

No code change necessary, probably fixed by previous commit.

modified:   tox.ini

* Fix E226 - missing whitespace around arithmetic operator

modified:   ssh-audit.py
modified:   tox.ini

* Fix W293 - blank line contains whitespace

modified:   ssh-audit.py
modified:   tox.ini

* Fix E221 - multiple spaces before operator

modified:   ssh-audit.py
modified:   tox.ini

* Update comment about Flake 8 E241

Lots of data is formatted as tables, so this warning is disabled for a
good reason.

modified:   tox.ini

* Fix E401 - multiple imports on one line

modified:   ssh-audit.py
modified:   tox.ini

* Do not ignore Flake8 warning F401

... as there were no errors in source code anyway.

modified:   tox.ini

* Fix F821 - undefined name

modified:   ssh-audit.py
modified:   tox.ini

* Reformat ignore section for Flake8

modified:   tox.ini

* Flake8 test suite

modified:   test/conftest.py
modified:   test/test_auditconf.py
modified:   test/test_banner.py
modified:   test/test_buffer.py
modified:   test/test_errors.py
modified:   test/test_output.py
modified:   test/test_resolve.py
modified:   test/test_socket.py
modified:   test/test_software.py
modified:   test/test_ssh1.py
modified:   test/test_ssh2.py
modified:   test/test_ssh_algorithm.py
modified:   test/test_utils.py
modified:   test/test_version_compare.py
modified:   tox.ini
This commit is contained in:
Jürgen Gmach 2020-06-09 23:54:07 +02:00 committed by GitHub
parent 29d874b450
commit 246a41d46f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 459 additions and 485 deletions

View File

@ -5,7 +5,7 @@ import re
from setuptools import setup
version = re.search('^VERSION\s*=\s*\'v(\d\.\d\.\d)\'', open('sshaudit/sshaudit.py').read(), re.M).group(1)
version = re.search(r'^VERSION\s*=\s*\'v(\d\.\d\.\d)\'', open('sshaudit/sshaudit.py').read(), re.M).group(1)
print("\n\nPackaging ssh-audit v%s...\n\n" % version)
with open("sshaudit/README.md", "rb") as f:

View File

@ -25,7 +25,20 @@
THE SOFTWARE.
"""
from __future__ import print_function
import base64, binascii, errno, hashlib, getopt, io, os, random, re, select, socket, struct, sys, json
import base64
import binascii
import errno
import getopt
import hashlib
import io
import json
import os
import random
import re
import select
import socket
import struct
import sys
VERSION = 'v2.2.1-dev'
@ -41,7 +54,7 @@ if sys.version_info >= (3,): # pragma: nocover
else: # pragma: nocover
import StringIO as _StringIO # pylint: disable=import-error
StringIO = BytesIO = _StringIO.StringIO
text_type = unicode # pylint: disable=undefined-variable
text_type = unicode # pylint: disable=undefined-variable # noqa: F821
binary_type = str
try: # pragma: nocover
# pylint: disable=unused-import
@ -190,9 +203,9 @@ class AuditConf(object):
elif o in ('-t', '--timeout'):
aconf.timeout = float(a)
aconf.timeout_set = True
if len(args) == 0 and aconf.client_audit == False:
if len(args) == 0 and aconf.client_audit is False:
usage_cb()
if aconf.client_audit == False:
if aconf.client_audit is False:
if oport is not None:
host = args[0]
else:
@ -798,7 +811,6 @@ class SSH2(object): # pylint: disable=too-few-public-methods
else:
host_key_types[host_key_type]['parsed'] = True
# Performs DH group exchanges to find what moduli are supported, and checks
# their size.
class GEXTest(object):
@ -865,7 +877,7 @@ class SSH2(object): # pylint: disable=too-few-public-methods
# got here, doesn't mean the server is vulnerable...
smallest_modulus = kex_group.get_dh_modulus_size()
except Exception as e: # pylint: disable=bare-except
except Exception: # pylint: disable=bare-except
pass
finally:
s.close()
@ -887,7 +899,7 @@ class SSH2(object): # pylint: disable=too-few-public-methods
kex_group.send_init_gex(s, bits, bits, bits)
kex_group.recv_reply(s, False)
smallest_modulus = kex_group.get_dh_modulus_size()
except Exception as e: # pylint: disable=bare-except
except Exception: # pylint: disable=bare-except
# import traceback
# print(traceback.format_exc())
pass
@ -897,7 +909,6 @@ class SSH2(object): # pylint: disable=too-few-public-methods
# connection.
s.close()
if smallest_modulus > 0:
kex.set_dh_modulus_size(gex_alg, smallest_modulus)
@ -919,6 +930,7 @@ class SSH2(object): # pylint: disable=too-few-public-methods
if reconnect_failed:
break
class SSH1(object):
class CRC32(object):
def __init__(self):
@ -935,8 +947,8 @@ class SSH1(object):
def calc(self, v):
# type: (binary_type) -> int
crc, l = 0, len(v)
for i in range(l):
crc, length = 0, len(v)
for i in range(length):
n = ord(v[i:i + 1])
n = n ^ (crc & 0xff)
crc = (crc >> 8) ^ self._table[n]
@ -1189,6 +1201,7 @@ class ReadBuf(object):
self._len = 0
super(ReadBuf, self).reset()
class WriteBuf(object):
def __init__(self, data=None):
# type: (Optional[binary_type]) -> None
@ -1783,10 +1796,9 @@ class SSH(object): # pylint: disable=too-few-public-methods
if software is not None:
if software.product not in vproducts:
unknown_software = True
#
# The code below is commented out because it would try to guess what the server is,
# usually resulting in wild & incorrect recommendations.
#
# if software is None:
# ssh_timeframe = self.get_ssh_timeframe(for_server)
# for product in vproducts:
@ -2057,7 +2069,6 @@ class SSH(object): # pylint: disable=too-few-public-methods
self.client_host = None
self.client_port = None
def _resolve(self, ipvo):
# type: (Sequence[int]) -> Iterable[Tuple[int, Tuple[Any, ...]]]
ipvo = tuple([x for x in utils.unique_seq(ipvo) if x in (4, 6)])
@ -2081,7 +2092,6 @@ class SSH(object): # pylint: disable=too-few-public-methods
out.fail('[exception] {0}'.format(e))
sys.exit(1)
# Listens on a server socket and accepts one connection (used for
# auditing client connections).
def listen_and_accept(self):
@ -2093,7 +2103,7 @@ class SSH(object): # pylint: disable=too-few-public-methods
s.bind(('0.0.0.0', self.__port))
s.listen()
self.__sock_map[s.fileno()] = s
except Exception as e:
except Exception:
print("Warning: failed to listen on any IPv4 interfaces.")
pass
@ -2105,7 +2115,7 @@ class SSH(object): # pylint: disable=too-few-public-methods
s.bind(('::', self.__port))
s.listen()
self.__sock_map[s.fileno()] = s
except Exception as e:
except Exception:
print("Warning: failed to listen on any IPv6 interfaces.")
pass
@ -2139,7 +2149,6 @@ class SSH(object): # pylint: disable=too-few-public-methods
c.settimeout(self.__timeout)
self.__sock = c
def connect(self):
# type: () -> None
err = None
@ -2357,7 +2366,6 @@ class KexDH(object): # pragma: nocover
self.__f = 0
self.__h_sig = 0
def set_params(self, g, p):
self.__g = g
self.__p = p
@ -2365,7 +2373,6 @@ class KexDH(object): # pragma: nocover
self.__x = 0
self.__e = 0
def send_init(self, s, init_msg=SSH.Protocol.MSG_KEXDH_INIT):
# type: (SSH.Socket) -> None
r = random.SystemRandom()
@ -2403,7 +2410,6 @@ class KexDH(object): # pragma: nocover
key_id = principles = None # pylint: disable=unused-variable
critical_options = extensions = None # pylint: disable=unused-variable
valid_after = valid_before = None # pylint: disable=unused-variable
nonce = ca_key = ca_key_type = None # pylint: disable=unused-variable
ca_key_e = ca_key_n = None # pylint: disable=unused-variable
@ -2455,12 +2461,10 @@ class KexDH(object): # pragma: nocover
# The principles, which are... I don't know what.
principles, principles_len, ptr = KexDH.__get_bytes(hostkey, ptr)
# The timestamp that this certificate is valid after.
valid_after = hostkey[ptr:ptr + 8]
# Skip over the timestamp that this certificate is valid after.
ptr += 8
# The timestamp that this certificate is valid before.
valid_before = hostkey[ptr:ptr + 8]
# Skip over the timestamp that this certificate is valid before.
ptr += 8
# TODO: validate the principles, and time range.
@ -3018,7 +3022,7 @@ def output_info(algs, software, client_audit, any_problems, padlen=0):
def output(banner, header, client_host=None, kex=None, pkm=None):
# type: (Optional[SSH.Banner], List[text_type], Optional[SSH2.Kex], Optional[SSH1.PublicKeyMessage]) -> None
client_audit = (client_host != None) # If set, this is a client audit.
client_audit = client_host is not None # If set, this is a client audit.
sshv = 1 if pkm is not None else 2
algs = SSH.Algorithms(pkm, kex)
with OutputBuffer() as obuf:
@ -3077,11 +3081,11 @@ def output(banner, header, client_host=None, kex=None, pkm=None):
perfect_config = output_recommendations(algs, software, maxlen)
output_info(algs, software, client_audit, not perfect_config)
# If we encountered any unknown algorithms, ask the user to report them.
if len(unknown_algorithms) > 0:
out.warn("\n\n!!! WARNING: unknown algorithm(s) found!: %s. Please email the full output above to the maintainer (jtesta@positronsecurity.com), or create a Github issue at <https://github.com/jtesta/ssh-audit/issues>.\n" % ','.join(unknown_algorithms))
class Utils(object):
@classmethod
def _type_err(cls, v, target):
@ -3204,6 +3208,7 @@ class Utils(object):
except: # pylint: disable=bare-except
return -1.0
def build_struct(banner, kex=None, pkm=None, client_host=None):
res = {
"banner": {
@ -3281,6 +3286,7 @@ def build_struct(banner, kex=None, pkm=None, client_host=None):
return res
def audit(aconf, sshv=None):
# type: (AuditConf, Optional[int]) -> None
out.batch = aconf.batch
@ -3350,9 +3356,11 @@ def audit(aconf, sshv=None):
utils = Utils()
out = Output()
def main():
conf = AuditConf.from_cmdline(sys.argv[1:], usage)
audit(conf)
if __name__ == '__main__': # pragma: nocover
main()

View File

@ -52,7 +52,6 @@ class TestErrors(object):
assert 'timed out' in lines[-1]
def test_recv_empty(self, output_spy, virtual_socket):
vsocket = virtual_socket
lines = self._audit(output_spy)
assert len(lines) == 1
assert 'did not receive banner' in lines[-1]

View File

@ -25,7 +25,7 @@ class TestResolve(object):
conf = self._conf()
output_spy.begin()
with pytest.raises(SystemExit):
r = list(s._resolve(conf.ipvo))
list(s._resolve(conf.ipvo))
lines = output_spy.flush()
assert len(lines) == 1
assert 'hostname nor servname provided' in lines[-1]
@ -40,7 +40,6 @@ class TestResolve(object):
assert len(r) == 0
def test_resolve_ipv4(self, virtual_socket):
vsocket = virtual_socket
conf = self._conf()
conf.ipv4 = True
s = self.ssh.Socket('localhost', 22)
@ -49,7 +48,6 @@ class TestResolve(object):
assert r[0] == (socket.AF_INET, ('127.0.0.1', 22))
def test_resolve_ipv6(self, virtual_socket):
vsocket = virtual_socket
s = self.ssh.Socket('localhost', 22)
conf = self._conf()
conf.ipv6 = True
@ -58,7 +56,6 @@ class TestResolve(object):
assert r[0] == (socket.AF_INET6, ('::1', 22))
def test_resolve_ipv46_both(self, virtual_socket):
vsocket = virtual_socket
s = self.ssh.Socket('localhost', 22)
conf = self._conf()
r = list(s._resolve(conf.ipvo))
@ -67,7 +64,6 @@ class TestResolve(object):
assert r[1] == (socket.AF_INET6, ('::1', 22))
def test_resolve_ipv46_order(self, virtual_socket):
vsocket = virtual_socket
s = self.ssh.Socket('localhost', 22)
conf = self._conf()
conf.ipv4 = True

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import pytest
@ -12,17 +11,17 @@ class TestSocket(object):
def test_invalid_host(self, virtual_socket):
with pytest.raises(ValueError):
s = self.ssh.Socket(None, 22)
self.ssh.Socket(None, 22)
def test_invalid_port(self, virtual_socket):
with pytest.raises(ValueError):
s = self.ssh.Socket('localhost', 'abc')
self.ssh.Socket('localhost', 'abc')
with pytest.raises(ValueError):
s = self.ssh.Socket('localhost', -1)
self.ssh.Socket('localhost', -1)
with pytest.raises(ValueError):
s = self.ssh.Socket('localhost', 0)
self.ssh.Socket('localhost', 0)
with pytest.raises(ValueError):
s = self.ssh.Socket('localhost', 65536)
self.ssh.Socket('localhost', 65536)
def test_not_connected_socket(self, virtual_socket):
sock = self.ssh.Socket('localhost', 22)

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import struct, os
import os
import struct
import pytest

View File

@ -105,15 +105,15 @@ class TestVersionCompare(object):
versions.append('2015.{0}'.format(i))
for i in range(72, 75):
versions.append('2016.{0}'.format(i))
l = len(versions)
for i in range(l):
length = len(versions)
for i in range(length):
v = versions[i]
s = self.get_dropbear_software(v)
assert s.compare_version(v) == 0
if i - 1 >= 0:
vbefore = versions[i - 1]
assert s.compare_version(vbefore) > 0
if i + 1 < l:
if i + 1 < length:
vnext = versions[i + 1]
assert s.compare_version(vnext) < 0
@ -164,15 +164,15 @@ class TestVersionCompare(object):
versions.append('6.{0}'.format(i))
for i in range(0, 4):
versions.append('7.{0}'.format(i))
l = len(versions)
for i in range(l):
length = len(versions)
for i in range(length):
v = versions[i]
s = self.get_openssh_software(v)
assert s.compare_version(v) == 0
if i - 1 >= 0:
vbefore = versions[i - 1]
assert s.compare_version(vbefore) > 0
if i + 1 < l:
if i + 1 < length:
vnext = versions[i + 1]
assert s.compare_version(vnext) < 0
@ -202,14 +202,14 @@ class TestVersionCompare(object):
versions.append('0.6.{0}'.format(i))
for i in range(0, 5):
versions.append('0.7.{0}'.format(i))
l = len(versions)
for i in range(l):
length = len(versions)
for i in range(length):
v = versions[i]
s = self.get_libssh_software(v)
assert s.compare_version(v) == 0
if i - 1 >= 0:
vbefore = versions[i - 1]
assert s.compare_version(vbefore) > 0
if i + 1 < l:
if i + 1 < length:
vnext = versions[i + 1]
assert s.compare_version(vnext) < 0

41
tox.ini
View File

@ -80,7 +80,7 @@ commands =
deps =
flake8
commands =
flake8 {posargs:{env:SSHAUDIT}}
flake8 {posargs:{env:SSHAUDIT} {toxinidir}/packages/setup.py {toxinidir}/test} --statistics
[testenv:vulture]
deps =
@ -137,42 +137,13 @@ max-module-lines = 2500
[flake8]
ignore =
# indentation contains tabs
W191,
# blank line contains whitespace
W293,
# indentation contains mixed spaces and tabs
E101,
# multiple spaces before operator
E221,
# multiple spaces after operator
E241,
# multiple imports on one line
E401,
# line too long
E501,
# module imported but unused
F401,
# undefined name
F821,
# these exceptions should be handled one by one
W191, # indentation contains tabs
E101, # indentation contains mixed spaces and tabs
E241, # multiple spaces after operator; should be kept for tabular data
E501, # line too long
E117, # over-indented
E126, # continuation line over-indented for hanging indent
E128, # continuation line under-indented for visual indent
E226, # missing whitespace around arithmetic operator
E231, # missing whitespace after ','
E251, # unexpected spaces around keyword / parameter equals
E261, # at least two spaces before inline comment
E265, # block comment should start with '# '
E301, # expected 1 blank line, found 0
E302, # expected 2 blank lines, found 1
E303, # too many blank lines (2)
E305, # expected 2 blank lines after class or function definition, found 1
E711, # comparison to None should be 'if cond is not None:'
E712, # comparison to False should be 'if cond is False:' or 'if not cond:'
E722, # do not use bare 'except'
E741, # ambiguous variable name 'l'
F601, # dictionary key 'ecdsa-sha2-1.3.132.0.10' repeated with different values
F841, # local variable 'e' is assigned to but never used
W504, # line break after binary operator
W605, # invalid escape sequence '\s'
W504, # line break after binary operator; this (or W503) has to stay