Skip to content

Commit

Permalink
FEATURE: Implement various analyzers for logical operations
Browse files Browse the repository at this point in the history
Those new analyzers can be used to perform logical operations on analyzers. They are rather some piece of meta analyzer
  • Loading branch information
d-Rickyy-b committed Oct 10, 2019
1 parent 627989a commit 94fc691
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 0 deletions.
7 changes: 7 additions & 0 deletions pastepwn/analyzers/logicalanalyzers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-

from .andanalyzer import AndAnalyzer
from .logicalbaseanalyzer import LogicalBaseAnalyzer
from .oranalyzer import OrAnalyzer

__all__ = ('LogicalBaseAnalyzer', 'AndAnalyzer', 'OrAnalyzer')
18 changes: 18 additions & 0 deletions pastepwn/analyzers/logicalanalyzers/andanalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from .logicalbaseanalyzer import LogicalBaseAnalyzer


class AndAnalyzer(LogicalBaseAnalyzer):
"""Meta analyzer which matches a paste if all of the passed analyzers match that paste"""
name = "AndAnalyzer"

def match(self, paste):
"""Returns True if all of the passed analyzers matched"""
if len(self.analyzers) == 0:
return False

for analyzer in self.analyzers:
if not analyzer.match(paste):
return False

return True
45 changes: 45 additions & 0 deletions pastepwn/analyzers/logicalanalyzers/logicalbaseanalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
from pastepwn.analyzers.basicanalyzer import BasicAnalyzer
from pastepwn.util import listify


class LogicalBaseAnalyzer(BasicAnalyzer):
"""Meta analyzer used to combine analyzers via a logical operator"""
name = "LogicalBaseAnalyzer"

def __init__(self, actions, analyzers, merge_actions=False):
"""
Meta analyzer used to combine analyzers via a logical operator
:param actions: A single action or a list of actions to be executed on every paste
:param analyzers: A single analyzer or a list of analyzers used to match pastes
"""
super().__init__(actions)
self.analyzers = listify(analyzers)

if len(self.analyzers) == 0:
self.logger.warning("You have not specified any analyzers inside '{}'".format(self.name))

if merge_actions:
self._merge_actions()

def _merge_actions(self):
"""
Merges the actions of the passed analyzers into this meta analyzer
If merged, the actions will be executed if this meta analyzer matches
:return: None
"""
for analyzer in self.analyzers:
for action in analyzer.actions:
self.actions.append(action)

def add_analyzer(self, analyzer):
"""
Add a new analyzer to the list of analyzers
:param analyzer: A single analyzer used to match pastes
:return:
"""
self.analyzers.append(analyzer)

def match(self, paste):
"""Must be overridden by the subclasses"""
raise NotImplementedError("match() function must be overridden in the subclasses!")
15 changes: 15 additions & 0 deletions pastepwn/analyzers/logicalanalyzers/oranalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from .logicalbaseanalyzer import LogicalBaseAnalyzer


class OrAnalyzer(LogicalBaseAnalyzer):
"""Meta analyzer which matches a paste if any of the passed analyzers match that paste"""
name = "OrAnalyzer"

def match(self, paste):
"""Returns True if all of the passed analyzers matched"""
for analyzer in self.analyzers:
if analyzer.match(paste):
return True

return False
Empty file.
54 changes: 54 additions & 0 deletions pastepwn/analyzers/logicalanalyzers/tests/andanalyzer_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
import unittest
from unittest import mock

from pastepwn.analyzers import AndAnalyzer


class TestAndAnalyzer(unittest.TestCase):
def setUp(self):
self.obj = mock.Mock()
self.gt = mock.Mock()
self.gt.match = mock.Mock(return_value=True)

self.gf = mock.Mock()
self.gf.match = mock.Mock(return_value=False)

def test_match_positive(self):
self.obj.body = "Test"
analyzer = AndAnalyzer(None, [self.gt])
self.assertTrue(analyzer.match(self.obj))

analyzer = AndAnalyzer(None, [self.gt, self.gt, self.gt])
self.assertTrue(analyzer.match(self.obj))

# Check if the analyzer returns false if there is at least one false result
analyzer = AndAnalyzer([], [self.gt, self.gf])
self.assertFalse(analyzer.match(self.obj))

analyzer = AndAnalyzer([], [self.gf, self.gf])
self.assertFalse(analyzer.match(self.obj))

analyzer = AndAnalyzer([], [self.gf, self.gf, self.gf, self.gt])
self.assertFalse(analyzer.match(self.obj))

def test_negative(self):
self.obj.body = ""

analyzer = AndAnalyzer([], None)
self.assertFalse(analyzer.match(self.obj))

analyzer = AndAnalyzer([], [])
self.assertFalse(analyzer.match(self.obj))

def test_actions_present(self):
analyzer = AndAnalyzer(self.obj, None)
self.assertEqual([self.obj], analyzer.actions)

def test_analyzers_present(self):
analyzer = AndAnalyzer(None, self.obj)
self.assertEqual([self.obj], analyzer.analyzers)


if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
import unittest
from unittest import mock

from pastepwn.analyzers.logicalanalyzers import LogicalBaseAnalyzer


class TestLogicalBaseAnalyzer(unittest.TestCase):
def setUp(self):
self.obj = mock.Mock()

def test_exception(self):
analyzer = LogicalBaseAnalyzer([], [])
self.assertRaises(NotImplementedError, analyzer.match, mock.Mock())

def test_actions_present(self):
analyzer = LogicalBaseAnalyzer(self.obj, None)
self.assertEqual([self.obj], analyzer.actions)

def test_analyzers_present(self):
analyzer = LogicalBaseAnalyzer(None, self.obj)
self.assertEqual([self.obj], analyzer.analyzers)

def test_merge_actions(self):
action1 = mock.Mock()
action2 = mock.Mock()
action3 = mock.Mock()

analyzer1 = mock.Mock()
analyzer1.actions = [action1, action2]
analyzer2 = mock.Mock()
analyzer2.actions = [action3]

analyzer = LogicalBaseAnalyzer(analyzers=[analyzer1, analyzer2], actions=[], merge_actions=True)
self.assertEqual(3, len(analyzer.actions), "Wrong amount of actions in LogicalBaseAnalyzer!")
self.assertEqual([action1, action2, action3], analyzer.actions, "Actions do not match!")


if __name__ == '__main__':
unittest.main()
53 changes: 53 additions & 0 deletions pastepwn/analyzers/logicalanalyzers/tests/oranalyzer_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
import unittest
from unittest import mock

from pastepwn.analyzers.logicalanalyzers import OrAnalyzer


class TestOrAnalyzer(unittest.TestCase):
def setUp(self):
self.obj = mock.Mock()
self.gt = mock.Mock()
self.gt.match = mock.Mock(return_value=True)

self.gf = mock.Mock()
self.gf.match = mock.Mock(return_value=False)

def test_match_positive(self):
self.obj.body = "Test"
analyzer = OrAnalyzer(None, [self.gt])
self.assertTrue(analyzer.match(self.obj))

analyzer = OrAnalyzer(None, [self.gt, self.gt, self.gt])
self.assertTrue(analyzer.match(self.obj))

analyzer = OrAnalyzer([], [self.gf, self.gf])
self.assertFalse(analyzer.match(self.obj))

analyzer = OrAnalyzer([], [self.gf, self.gf, self.gf])
self.assertFalse(analyzer.match(self.obj))

analyzer = OrAnalyzer([], [self.gf, self.gf, self.gf, self.gt])
self.assertTrue(analyzer.match(self.obj))

def test_negative(self):
self.obj.body = ""

analyzer = OrAnalyzer([], None)
self.assertFalse(analyzer.match(self.obj))

analyzer = OrAnalyzer([], [])
self.assertFalse(analyzer.match(self.obj))

def test_actions_present(self):
analyzer = OrAnalyzer(self.obj, None)
self.assertEqual([self.obj], analyzer.actions)

def test_analyzers_present(self):
analyzer = OrAnalyzer(None, self.obj)
self.assertEqual([self.obj], analyzer.analyzers)


if __name__ == '__main__':
unittest.main()

0 comments on commit 94fc691

Please sign in to comment.