/
basicanalyzer.py
131 lines (109 loc) · 4.79 KB
/
basicanalyzer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# -*- coding: utf-8 -*-
import logging
from pastepwn.actions import BasicAction
from pastepwn.errors import InvalidActionError
from pastepwn.util import listify
class BasicAnalyzer(object):
"""Basic analyzer class"""
name = "BasicAnalyzer"
def __init__(self, actions, identifier=None):
"""
Basic analyzer which is extended to create other analyzer subclasses
:param actions: A single action or a list of actions to be executed on every paste
:param identifier: The name or unique identifier for this specific analyzer
"""
self.logger = logging.getLogger(__name__)
self.actions = listify(actions)
self.identifier = identifier or self.name
# Check if passed action is an instance of an analyzer and not a class - see #175
# Raises an error if any action is not an object inheriting from BasicAaction
for action in self.actions:
self._check_action(action)
def add_action(self, action):
"""
Adds a new action to the already present actions
:param action: New action to add to the present actions
:return: None
"""
self._check_action(action)
self.actions.append(action)
def match(self, paste):
"""
Checks if a certain paste is matched by the conditions set for this analyzer
:param paste: A :class:`pastepwn.core.paste` object which should be matched
:return: :obj:`bool` if the paste has been matched
"""
raise NotImplementedError("Your analyzer must implement the match method!")
def _check_action(self, action):
"""Check if a passed action is a subclass of BasicAction"""
if not isinstance(action, BasicAction):
if isinstance(action, type):
error_msg = "You passed a class as action for '{}' but an instance of an action was expected!".format(self.identifier)
else:
error_msg = "You did not pass an action object - inheriting from BasicAction - to '{}'".format(self.identifier)
self.logger.error(error_msg)
raise InvalidActionError(error_msg)
def __and__(self, other):
"""
Return a new dstream with the same elements.
Args:
self: (todo): write your description
other: (todo): write your description
"""
return MergedAnalyzer(self, and_analyzer=other)
def __or__(self, other):
"""
Shared version of self is_analyzer.
Args:
self: (todo): write your description
other: (todo): write your description
"""
return MergedAnalyzer(self, or_analyzer=other)
def __repr__(self):
"""
Return a unique identifier for a class.
Args:
self: (todo): write your description
"""
if self.identifier is None:
self.identifier = self.__class__.__name__
return self.identifier
class MergedAnalyzer(BasicAnalyzer):
"""
Combination class to combine multiple analyzers into a single one
Doesn't need to be created manually - use the binary operators (& and |) to combine multiple analyzers.
"""
name = "MergedAnalyzer"
def __init__(self, base_analyzer, and_analyzer=None, or_analyzer=None):
"""
Initialize the action.
Args:
self: (todo): write your description
base_analyzer: (todo): write your description
and_analyzer: (todo): write your description
or_analyzer: (todo): write your description
"""
self._base_analyzer = base_analyzer
self._and_analyzer = and_analyzer
self._or_analyzer = or_analyzer
if self._and_analyzer:
actions = base_analyzer.actions + self._and_analyzer.actions
identifier = "({} && {})".format(base_analyzer.identifier, self._and_analyzer)
elif self._or_analyzer:
actions = base_analyzer.actions + self._or_analyzer.actions
identifier = "({} || {})".format(base_analyzer.identifier, self._or_analyzer)
else:
actions = []
identifier = "Broken analyzer"
self.logger.error("Neither and_analyzer nor or_analyzer are set!")
super().__init__(actions, identifier=identifier)
def match(self, paste):
"""
Checks if a certain paste is matched by the conditions set for this analyzer
:param paste: A :class:`pastepwn.core.paste` object which should be matched
:return: :obj:`bool` if the paste has been matched
"""
if self._and_analyzer:
return bool(self._base_analyzer.match(paste)) and bool(self._and_analyzer.match(paste))
elif self._or_analyzer:
return bool(self._base_analyzer.match(paste)) or bool(self._or_analyzer.match(paste))