diff --git a/src/pyrad3/client.py b/src/pyrad3/client.py index 5de3040..152227b 100644 --- a/src/pyrad3/client.py +++ b/src/pyrad3/client.py @@ -74,7 +74,9 @@ class Client(H.Host): # have any implementation yet for non-Linux systems. # Better to fail loudly than to do something unexpected silently. self._socket.setsockopt( - socket.SOL_SOCKET, socket.SO_BINDTODEVICE, self.interface.encode("utf-8"), + socket.SOL_SOCKET, + socket.SO_BINDTODEVICE, + self.interface.encode("utf-8"), ) self._poll = select.poll() self._poll.register(self._socket, select.POLLIN) diff --git a/src/pyrad3/dictionary.py b/src/pyrad3/dictionary.py index ec64a7a..263b260 100644 --- a/src/pyrad3/dictionary.py +++ b/src/pyrad3/dictionary.py @@ -28,7 +28,11 @@ class ParseError(Exception): """RADIUS Dictionary Parser Error""" def __init__( - self, filename: str, msg: str = None, line: Optional[int] = None, **data, + self, + filename: str, + msg: str = None, + line: Optional[int] = None, + **data, ): super().__init__() self.msg = msg @@ -59,7 +63,9 @@ def dict_parser( inner_filename = tokens[1] except IndexError as exc: raise ParseError( - filename, "$INCLUDE is missing a filename", line_num, + filename, + "$INCLUDE is missing a filename", + line_num, ) from exc if not isabs(tokens[1]): path = dirname(filename) @@ -215,7 +221,9 @@ class Dictionary: filename = self.filestack[-1] if self.cur_vendor != self.rfc_vendor: raise ParseError( - filename, "vendor-begin sections are not allowed to be nested", line_num, + filename, + "vendor-begin sections are not allowed to be nested", + line_num, ) if len(tokens) != 2: raise ParseError( @@ -238,7 +246,9 @@ class Dictionary: filename = self.filestack[-1] if len(tokens) != 2: raise ParseError( - filename, "Incorrect number of tokens for end-vendor statement", line_num, + filename, + "Incorrect number of tokens for end-vendor statement", + line_num, ) if self.cur_vendor.name != tokens[1]: raise ParseError( @@ -280,7 +290,9 @@ class Dictionary: encrypt = Encrypt(int(value)) # type: ignore except (ValueError, TypeError) as exc: raise ParseError( - filename, f"Illegal attribute encryption {value}", line_num, + filename, + f"Illegal attribute encryption {value}", + line_num, ) from exc else: raise ParseError(filename, "Unknown attribute flag {key}", line_num) @@ -306,7 +318,9 @@ class Dictionary: ) if code_num < 0: raise ParseError( - filename, "negative attribute codes are not allowed", line_num, + filename, + "negative attribute codes are not allowed", + line_num, ) codes.append(code_num) return codes @@ -316,7 +330,9 @@ class Dictionary: filename = self.filestack[-1] if not len(tokens) in [4, 5]: raise ParseError( - filename, "Incorrect number of tokens for attribute definition", line_num, + filename, + "Incorrect number of tokens for attribute definition", + line_num, ) has_tag, encrypt = self._parse_attribute_flags(tokens, line_num) @@ -347,11 +363,17 @@ class Dictionary: raise ParseError(filename, f"Illegal type: {datatype}", line_num) from exc attribute = Attribute( - name, codes[-1], attribute_type, {}, has_tag, encrypt, len(codes) > 1, + name, + codes[-1], + attribute_type, + {}, + has_tag, + encrypt, + len(codes) > 1, ) - attrcode: Union[int, Tuple[int, ...]] = codes[0] if len(codes) == 1 else tuple( - codes + attrcode: Union[int, Tuple[int, ...]] = ( + codes[0] if len(codes) == 1 else tuple(codes) ) self.cur_vendor.attrs[attrcode] = attribute @@ -364,8 +386,8 @@ class Dictionary: ) else: LOG.info("Register Attribute %s", attribute.name) - attrcode: Union[int, Tuple[int, ...]] = codes[0] if len(codes) == 1 else tuple( - codes + attrcode: Union[int, Tuple[int, ...]] = ( + codes[0] if len(codes) == 1 else tuple(codes) ) self.attrindex[attrcode] = attribute self.attrindex[name] = attribute @@ -375,7 +397,9 @@ class Dictionary: filename = self.filestack[-1] if len(tokens) != 4: raise ParseError( - filename, "Incorrect number of tokens for VALUE definition", line_num, + filename, + "Incorrect number of tokens for VALUE definition", + line_num, ) (attr_name, key, vvalue) = tokens[1:] @@ -393,7 +417,9 @@ class Dictionary: attribute = self.attrindex[attr_name] except KeyError as exc: raise ParseError( - filename, f"ATTRIBUTE {attr_name} has not been defined yet", line_num, + filename, + f"ATTRIBUTE {attr_name} has not been defined yet", + line_num, ) from exc try: datatype = str(attribute.datatype).split(".")[1] diff --git a/src/pyrad3/packet.py b/src/pyrad3/packet.py index 76ab2ae..1891033 100644 --- a/src/pyrad3/packet.py +++ b/src/pyrad3/packet.py @@ -83,8 +83,7 @@ class Packet(OrderedDict): return reply def send(self): - """Send the packet to the Client/Server. - """ + """Send the packet to the Client/Server.""" self.host._send_packet(self) # pylint: disable=protected-access def verify_reply(self, raw_reply: bytes): @@ -132,7 +131,11 @@ class Packet(OrderedDict): if self.code in (Code.AccessRequest, Code.StatusServer): hmac_builder.update(self.authenticator) - elif self.code in (Code.AccessAccept, Code.AccessChallenge, Code.AccessReject,): + elif self.code in ( + Code.AccessAccept, + Code.AccessChallenge, + Code.AccessReject, + ): hmac_builder.update(self.request.authenticator) else: hmac_builder.update(16 * b"\00") @@ -265,7 +268,10 @@ class AuthPacket(Packet): # pylint: disable=abstract-method except KeyError: challenge = self.authenticator return validate_chap_password( - chap_id, challenge, chap_password, password, # type: ignore + chap_id, + challenge, + chap_password, + password, # type: ignore ) diff --git a/src/pyrad3/utils.py b/src/pyrad3/utils.py index c2954a4..38c83d5 100644 --- a/src/pyrad3/utils.py +++ b/src/pyrad3/utils.py @@ -16,6 +16,15 @@ from pyrad3.types import Code, Datatype RANDOM_GENERATOR = secrets.SystemRandom() MD5 = hashlib.md5 +# Table used to look up the struct parameter for the +# corresponding vendor definition value +PACK_TABLE = { + 0: "", + 1: "B", + 2: "H", + 4: "I", +} + class PacketError(Exception): """Exception for Invalid Packets""" @@ -143,14 +152,6 @@ def pre_decode_attributes( # pylint: disable=too-many-branches return attributes -PACK_TABLE = { - 0: "", - 1: "B", - 2: "H", - 4: "I", -} - - def get_vendor_format(rad_dict: Dictionary, vendor_id: int) -> Tuple[str, int]: """Get the vendor format @@ -321,7 +322,9 @@ def password_decode( def create_chap_password( - chap_id: bytes, challenge: bytes, plaintext_password: bytes, + chap_id: bytes, + challenge: bytes, + plaintext_password: bytes, ) -> bytes: """Create the CHAP Password with the chap_id and challenge. @@ -338,14 +341,20 @@ def create_chap_password( def validate_chap_password( - chap_id: bytes, challenge: bytes, chap_password: bytes, plaintext_password: bytes, + chap_id: bytes, + challenge: bytes, + chap_password: bytes, + plaintext_password: bytes, ) -> bool: """Validate the CHAP password against the given plaintext password""" return chap_password == create_chap_password(chap_id, challenge, plaintext_password) def salt_encrypt( - secret: bytes, authenticator: bytes, value: bytes, salt: Optional[int] = None, + secret: bytes, + authenticator: bytes, + value: bytes, + salt: Optional[int] = None, ) -> bytes: """Salt Encrypt the given value""" if salt is None: diff --git a/tests/test_dictionary.py b/tests/test_dictionary.py index bbbfda1..3072cd3 100644 --- a/tests/test_dictionary.py +++ b/tests/test_dictionary.py @@ -119,7 +119,8 @@ def test_valid_attribute_numbers(number): @pytest.mark.parametrize( - "invalid_number", ["1000", "ABCD", "-1", "inf", "INF", "-INF", "2e4", "2.5e3"], + "invalid_number", + ["1000", "ABCD", "-1", "inf", "INF", "-INF", "2e4", "2.5e3"], ) def test_invalid_attribute_numbers(invalid_number): dictionary = StringIO(f"ATTRIBUTE NAME {invalid_number} integer64") @@ -299,7 +300,8 @@ def test_invalid_datatypes_in_vendor_space(datatype): @pytest.mark.parametrize( - "invalid_number", ["ABCD", "-1", "inf", "INF", "-INF", "0.1", "2e4", "2.5e3"], + "invalid_number", + ["ABCD", "-1", "inf", "INF", "-INF", "0.1", "2e4", "2.5e3"], ) def test_invalid_value_numbers(invalid_number): dictionary = StringIO(