Exemplo n.º 1
0
class CommandNotify(Command):

    HANDLER_ID = 'NOTIFY'
    EXTENSION_NAME = 'enotify'
    TAGGED_ARGS = {
        'from': Tag('FROM', (StringList(1), )),
        'importance': Tag('IMPORTANCE', (StringList(1), )),
        'options': Tag('OPTIONS', (StringList(), )),
        'message': Tag('MESSAGE', (StringList(1), )),
    }
    POSITIONAL_ARGS = [StringList(length=1)]

    def evaluate(self, message: Message, state: EvaluationState) -> None:
        notify_from = notify_importance = self.notify_message = None
        notify_options = []  # type: ignore
        if 'from' in self.tagged_args:
            notify_from = self.tagged_args['from'][1][0]  # type: ignore
        if 'importance' in self.tagged_args:
            notify_importance = self.tagged_args['importance'][1][
                0]  # type: ignore
        if 'options' in self.tagged_args:
            notify_options = self.tagged_args['options'][1]  # type: ignore
        notify_message = None
        if 'message' in self.tagged_args:
            notify_message = self.tagged_args['message'][1][0]  # type: ignore
        notify_method = self.positional_args[0][0]  # type: ignore

        state.check_required_extension('enotify', 'NOTIFY')
        notify_from = expand_variables(notify_from, state)  # type: ignore
        notify_importance = expand_variables(notify_importance,
                                             state)  # type: ignore
        notify_options = list(
            map(lambda s: expand_variables(s, state), notify_options))
        notify_message = expand_variables(notify_message,
                                          state)  # type: ignore
        notify_method = expand_variables(notify_method, state)

        m = re.match('^([A-Za-z][A-Za-z0-9.+-]*):', notify_method)
        if not m:
            raise RuleSyntaxError(
                "Notification method must be an URI, e.g. 'mailto:[email protected]'"
            )
        if notify_importance and notify_importance not in ["1", "2", "3"]:
            raise RuleSyntaxError(
                "Illegal notify importance '%s' encountered" %
                notify_importance)
        notify_method_cls = ExtensionRegistry.get_notification_method(
            m.group(1).lower())
        if not notify_method_cls:
            raise RuleSyntaxError("Unsupported notification method '%s'" %
                                  m.group(1))
        (res, msg) = notify_method_cls.test_valid(notify_method)
        if not res:
            raise RuleSyntaxError(msg)

        state.actions.append(
            'notify',
            (notify_method, notify_from, notify_importance, notify_options,
             notify_message)  # type: ignore
        )
Exemplo n.º 2
0
class TestAddress(Test):

    HANDLER_ID: Text = 'ADDRESS'
    TAGGED_ARGS = {
        'comparator': Comparator(),
        'match_type': MatchType(),
        'address_part': Tag(('LOCALPART', 'DOMAIN', 'ALL')),
    }
    POSITIONAL_ARGS = [
        StringList(),
        StringList(),
    ]

    def __init__(self,
                 arguments: Optional[List[Union['TagGrammar', SupportsInt,
                                                List[Union[
                                                    Text, 'String']]]]] = None,
                 tests: Optional[List['Test']] = None) -> None:
        super().__init__(arguments, tests)

        self.headers, self.keylist = self.positional_args
        self.match_type = self.comparator = self.address_part = None
        if 'comparator' in self.tagged_args:
            self.comparator = self.tagged_args['comparator'][1][
                0]  # type: ignore
        if 'match_type' in self.tagged_args:
            self.match_type = self.tagged_args['match_type'][0]
        if 'address_part' in self.tagged_args:
            self.address_part = self.tagged_args['address_part'][0]

    def evaluate(self, message: Message, state: EvaluationState) -> bool:
        if not isinstance(self.keylist, list):
            raise ValueError('TestAddress keylist not iterable')

        if not isinstance(self.headers, list):
            raise ValueError('TestAddress headers not iterable')

        header_values: List[Text] = []
        for header in self.headers:
            header = expand_variables(header, state)
            # TODO: section 5.1: we should restrict the allowed headers to
            # those headers that contain an "address-list". this includes at
            # least: from, to, cc, bcc, sender, resent-from, resent-to.
            header_values.extend(message.get_all(header, []))
        addresses: List[Text] = []
        for msg_address in email.utils.getaddresses(header_values):
            if msg_address[1] != '':
                addresses.append(
                    sifter.grammar.string.address_part(
                        msg_address[1], cast(Text, self.address_part)))
        for address in addresses:
            for key in self.keylist:
                key = expand_variables(key, state)
                if sifter.grammar.string.compare(address, key, state,
                                                 self.comparator,
                                                 cast(Text, self.match_type)):
                    return True
        return False
Exemplo n.º 3
0
class CommandSet(Command):

    HANDLER_ID = 'SET'
    EXTENSION_NAME = 'variables'
    TAGGED_ARGS = {
        'lower': Tag('LOWER'),
        'upper': Tag('UPPER'),
        'lowerfirst': Tag('LOWERFIRST'),
        'upperfirst': Tag('UPPERFIRST'),
        'quotewildcard': Tag('QUOTEWILDCARD'),
        'quoteregex': Tag('QUOTEREGEX'),
        'encodeurl': Tag('ENCODEURL'),
        'length': Tag('LENGTH'),
    }
    POSITIONAL_ARGS = [
        StringList(length=1),
        StringList(length=1),
    ]

    def evaluate(self, message: Message, state: EvaluationState) -> None:
        state.check_required_extension('variables', 'VARIABLES')

        variable_modifier = self.tagged_args
        variable_name = self.positional_args[0][0]  # type: ignore
        if (not re.match(r'^[A-Za-z_][A-Za-z0-9_]*$', variable_name)):
            raise RuleSyntaxError("Illegal variable name '%s' encountered" %
                                  variable_name)
        variable_value: Text = self.positional_args[1][0]  # type: ignore

        variable_value = expand_variables(variable_value, state)
        if 'lower' in variable_modifier:
            variable_value = variable_value.lower()
        if 'upper' in variable_modifier:
            variable_value = variable_value.upper()
        if 'lowerfirst' in variable_modifier:
            variable_value = variable_value[:1].lower() + variable_value[1:]
        if 'upperfirst' in variable_modifier:
            variable_value = variable_value[:1].upper() + variable_value[1:]
        if 'quotewildcard' in variable_modifier:
            variable_value = variable_value.replace('*', '\\*')
            variable_value = variable_value.replace('?', '\\?')
            variable_value = variable_value.replace('\\', '\\\\')
        if 'quoteregex' in variable_modifier:
            variable_value = re.escape(variable_value)
        if 'encodeurl' in variable_modifier:
            variable_value = quote(variable_value, safe='-._~')
        if 'length' in variable_modifier:
            variable_value = "" + str(len(variable_value))
        state.named_variables[variable_name] = variable_value
Exemplo n.º 4
0
class TestSize(Test):

    HANDLER_ID = 'SIZE'
    TAGGED_ARGS = {
        'size': Tag(('OVER', 'UNDER'), (Number(), )),
    }

    COMPARISON_FNS: Dict[Text, Callable[[Any, Any], bool]] = {
        'OVER': operator.gt,
        'UNDER': operator.lt,
    }

    def evaluate(self, message: Message, state: EvaluationState) -> bool:
        comparison_fn = self.COMPARISON_FNS[self.tagged_args['size']
                                            [0]]  # type: ignore
        comparison_size = self.tagged_args['size'][1]

        # FIXME: size is defined as number of octets, whereas this gives us
        # number of characters
        message_size = len(message.as_string())
        return comparison_fn(message_size, comparison_size)
Exemplo n.º 5
0
def test_not_allowed_single_tag() -> None:
    # test the case for a non-list single tag name. test when the tag is a
    # substring of the allowed tag.
    mock_validator = TagValidator('ISFOO')
    assert mock_validator.validate([GrammarTag('IS')], 0) == 0
Exemplo n.º 6
0
def test_not_allowed_tag() -> None:
    mock_validator = TagValidator([
        'MOCK',
        'FOO',
    ])
    assert mock_validator.validate([GrammarTag('IS')], 0) == 0
Exemplo n.º 7
0
def test_allowed_single_tag() -> None:
    # test the case for a non-list single tag name
    mock_validator = TagValidator('IS')
    assert mock_validator.validate([GrammarTag('IS')], 0) == 1