예제 #1
0
    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
예제 #3
0
    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.')
예제 #4
0
    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.')
예제 #5
0
    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)
예제 #6
0
    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)
예제 #7
0
    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
예제 #8
0
    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)
예제 #9
0
    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)
예제 #10
0
    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)
예제 #11
0
    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)
예제 #12
0
    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)
예제 #13
0
    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)