diff --git a/pyzkaccess/cli.py b/pyzkaccess/cli.py index 1c1ccdb..4326135 100644 --- a/pyzkaccess/cli.py +++ b/pyzkaccess/cli.py @@ -4,6 +4,7 @@ import ipaddress import os import re +import string import sys import traceback from datetime import date, datetime, time @@ -1199,17 +1200,7 @@ def connect(self, ip: str, *, model: str = "ZK400") -> ZKCommand: raise FireError(f"Unknown device model '{model}', possible values are: ZK100, ZK200, ZK400") if not connstr: - try: - if not isinstance(ip, str): # python-fire may pass here int, tuple, etc. - raise ValueError("IP address must be a string") - ip_addr = ipaddress.ip_address(ip) - except ValueError: - raise FireError( - f"Bad IPv4 address: '{ip}'. Note: if you want to pass a connection string, set IP to " - f"'ENV' and use the PYZKACCESS_CONNECT_CONNSTR environment variable" - ) - - connstr = f"protocol=TCP,ipaddress={ip_addr},port=4370,timeout=4000,passwd=" + connstr = f"protocol=TCP,ipaddress={self._parse_ip(ip)},port=4370,timeout=4000,passwd=" zkcmd = ZKCommand(ZKAccess(connstr, device_model=device_model, dllpath=self._dllpath)) @@ -1227,7 +1218,7 @@ def search_devices(self, *, broadcast_address: str = "255.255.255.255"): converter = TextConverter(formatter) def _search_devices(): - devices = ZKAccess.search_devices(broadcast_address, dllpath=self._dllpath) + devices = ZKAccess.search_devices(self._parse_ip(broadcast_address), dllpath=self._dllpath) for device in devices: values = [device.mac, device.ip, device.serial_number, device.model.name, device.version] yield dict(zip(headers, values)) @@ -1242,11 +1233,32 @@ def change_ip(self, mac_address: str, new_ip: str, *, broadcast_address: str = " Args: mac_address: MAC address of a device - new_ip: new IP address to be set + new_ip: new IPv4 address to be set broadcast_address: broadcast network address to send broadcast packets to. Default: 255.255.255.255 """ - ZKAccess.change_ip(mac_address, new_ip, broadcast_address, ChangeIPProtocol.udp, self._dllpath) + ZKAccess.change_ip(self._parse_mac(mac_address), self._parse_ip(new_ip), self._parse_ip(broadcast_address), ChangeIPProtocol.udp, self._dllpath) + + @staticmethod + def _parse_ip(value: Any) -> str: + try: + if not isinstance(value, str): # python-fire may pass here int, tuple, etc. + raise ValueError("Bad IPv4 address") + ip_addr = ipaddress.ip_address(value) + except ValueError: + raise FireError(f"Bad IPv4 address: '{value}'") + + return str(ip_addr) + + @staticmethod + def _parse_mac(value: Any) -> str: + if not isinstance(value, str): + raise ValueError("Bad MAC address") + + if not re.match(r"^[0-9a-fA-F]{2}([:-]?[0-9a-fA-F]{2}){5}$", value): + raise FireError(f"Bad MAC address '{value}'") + + return value class WriteFile(wrapt.ObjectProxy): @@ -1271,7 +1283,7 @@ def main(): sys.stderr.write(traceback.format_exc()) sys.stderr.write( f"ERROR: {e}\n" - f"Please ensure that the environment is set up correctly by running the `pyzkaccess setup` command\n" + f"Note: You can ensure that the environment is set up correctly by running the `pyzkaccess setup` command\n" ) sys.exit(2)