def load(self): """ Load the configuration file and parse. Spaces, single and double quotes will be stripped. Lines beginning in # will be ignored. :returns: obj -- An instance of `blackhole.config.Config` """ if self.config_file is None: return self if not os.access(self.config_file, os.R_OK): msg = 'Config file does not exist or is not readable.' raise ConfigException(msg) for line in open(self.config_file, 'r').readlines(): line = line.strip() if line.startswith('#'): continue try: key, value = line.split('=') except ValueError: continue key, value = key.strip(), value.strip() key = "_{}".format(key) value = value.replace('"', '').replace("'", '') setattr(self, key, value) return self
def test_run_load_test_fails(): cfile = create_config(("listen=127.0.0.1:0", )) with mock.patch("sys.argv", ["blackhole", "-t", "-c", cfile]), mock.patch( "blackhole.config.Config.test", side_effect=ConfigException()), pytest.raises(SystemExit) as exc: run() assert exc.value.code == 64
def test_mode(self): """ Validate the response mode. Valid options are: 'accept', 'bounce' and 'random'. :raises: `blackhole.config.ConfigException` """ if self.mode not in ('accept', 'bounce', 'random'): raise ConfigException('Mode must be accept, bounce or random.')
def test_delay(self): """ Validate the delay period. Delay must be lower than the timeout. :raises: `blackhole.config.ConfigException` """ if self.delay and self.delay >= self.timeout: raise ConfigException('Delay must be lower than timeout.')
def test_timeout(self): """ Validate timeout - only allow a valid integer value in seconds. :raises: `blackhole.exceptions.ConfigException` """ try: _ = self.timeout except ValueError: msg = '{} is not a valid number of seconds.'.format(self._timeout) raise ConfigException(msg)
def test_tls_port(self): """ Validate TLS port number. :raises: `blackhole.exceptions.ConfigException` .. note:: Only verifies port is a valid integer, does not verify port is available or not in use. """ if self._tls_port is None: return try: _ = self.tls_port except ValueError: msg = '{} is not a valid port number.'.format(self._tls_port) raise ConfigException(msg) if self.port == self.tls_port: raise ConfigException('SMTP and SMTP/TLS ports must be different.') self._port_permissions(self.tls_port)
def _port_permissions(self, port): """ Validate that we have permission to use the port and it's not in use. :param port: :type port: int :raises: ConfigException """ self._min_max_port(port) if os.getuid() is not 0 and port < 1024: msg = 'You do not have permission to use port {}'.format(port) raise ConfigException(msg) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.bind(('127.0.0.1', port)) except OSError as err: errmsg = err.strerror.lower() msg = 'Could not use port {}, {}'.format(port, errmsg) raise ConfigException(msg) finally: sock.close() del sock
def _min_max_port(self, port): """ The minimum and maximum allowed port. :param port: The port. :type port: int :raises: `blackhole.config.ConfigException` .. note:: On Linux the minimum is 1 and maximum is 65535. """ min, max = 1, 65535 if port < min: msg = '''Port number {} is not usable because it is less than '''\ '''{} which is the lowest available port.'''.format(port, min) raise ConfigException(msg) if port > max: msg = '''Port number {} is not usable because it is less than '''\ '''{} which is the highest available port'''.format(port, max) raise ConfigException(msg)
def test_address(self): """ Validate IPv4 address format. :raises: `blackhole.exceptions.ConfigException` .. note:: Classifies 'localhost' as a valid IPv4 address. """ address = re.match(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", self.address) if self.address not in ('localhost', ) and not address: msg = '{} is not a valid IPv4 address.'.format(self._address) raise ConfigException(msg)
def test_group(self): """ Validate group exists in UNIX group database. :raises: `blackhole.exceptions.ConfigException` .. note:: Defaults to `grp.getgrgid.gr_name` if no group is specified. """ try: grp.getgrnam(self.group) except KeyError: msg = '{} is a not a valid group.'.format(self._group) raise ConfigException(msg)
def test_user(self): """ Validate user exists in UNIX password database. :raises: `blackhole.exceptions.ConfigException` .. note:: Defaults to `getpass.getuser` if no user is specified. """ try: pwd.getpwnam(self.user) except KeyError: msg = '{} is not a valid user.'.format(self._user) raise ConfigException(msg)
def test_port(self): """ Validate port number. :raises: `blackhole.exceptions.ConfigException` .. note:: Only verifies port is a valid integer, does not verify port is available or not in use. """ try: _ = self.port except ValueError: msg = '{} is not a valid port number.'.format(self._port) raise ConfigException(msg) self._port_permissions(self.port)
def test_tls_settings(self): """ Validate TLS configuration. :raises: `blackhole.exceptions.ConfigException` .. note:: Verifies if you provide all TLS settings, not just some. """ port = self.tls_port if self.tls_port is not None else False cert = os.access(self.tls_cert, os.R_OK) if self.tls_cert else False key = os.access(self.tls_key, os.R_OK) if self.tls_key else False if (port, cert, key) == (False, False, False): return if not all((port, cert, key)): msg = '''To use TLS you must supply a port, certificate file '''\ '''and key file.''' raise ConfigException(msg)