Skip to content

Commit

Permalink
🗓 Sep 11, 2023 8:11:05 PM
Browse files Browse the repository at this point in the history
✨ callback method for user supplied functions
✨ unicode_escape
🐙 diff return only changes
🧪 tests added/updated
🤖 types added/updated
  • Loading branch information
securisec committed Sep 12, 2023
1 parent 4b511a5 commit 291f773
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 5 deletions.
2 changes: 2 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ New ideas:
☐ ✨ whitespace encoding https://www.dcode.fr/whitespace-language
☐ 🐙 diff show results only
☐ ✨ brainfuck encoder/decoder
☐ ✨ spoon encoder/decoder

Bug:

Expand Down Expand Up @@ -59,6 +60,7 @@ Misc:
☐ cyberchef recipe to chepy recipe converter

Archive:
✔ ✨ callback function that can take a python function and run it over state. handle recipes for this
✔ ✨ automatic delimiter detect
✔ ✨ rabbit encryption
✔ ✨ cetacean encode/decode
Expand Down
28 changes: 27 additions & 1 deletion chepy/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from configparser import ConfigParser
from importlib.machinery import SourceFileLoader
from pprint import pformat
from typing import Any, Dict, List, Mapping, Tuple, Union
from typing import Any, Dict, List, Mapping, Tuple, Union, Callable
from urllib.parse import urljoin

import lazy_import
Expand Down Expand Up @@ -1367,3 +1367,29 @@ def set_plugin_path(self, path: str) -> None: # pragma: no cover
return None
else:
raise AttributeError("The path does not exist")

def callback(self, callback_function: Callable[[Any], Any]):
"""Run any user defined python function against the state.
This method is not recorded in the recipes
Args:
callback_function (Callable[[Any], Any]): The function to run. The function should take one argument (the state is passed to it). It can return Any
Examples:
from chepy import Chepy
def cb(data):
return data * 2
c = Chepy('abc').callback(cb)
# state is now abcabc
Returns:
Chepy: The Chepy object.
"""
# dont run if from cli
if sys.stdout.isatty(): # pragma: no cover
logging.warning("callback cannot be used via the cli")
return self
self.state = callback_function(self.state)
return self
1 change: 1 addition & 0 deletions chepy/core.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,4 @@ class ChepyCore:
def plugins(self: ChepyCoreT, enable: Literal['true', 'false']) -> None: ...
def set_plugin_path(self: ChepyCoreT, path: str) -> None: ...
def subsection(self: ChepyCoreT, pattern: str, methods: List[Tuple[Union[str, object], dict]], group: int=...) -> ChepyCoreT: ...
def callback(self: ChepyCoreT, callback_function: Callable[[Any], Any]) -> ChepyCoreT: ...
27 changes: 27 additions & 0 deletions chepy/modules/dataformat.py
Original file line number Diff line number Diff line change
Expand Up @@ -1812,3 +1812,30 @@ def from_messagepack(self) -> DataFormatT:
"""
self.state = msgpack.unpackb(self.state, raw=False)
return self

@ChepyDecorators.call_stack
def unicode_escape(
self, padding: int = 0, uppercase_hex: bool = False
) -> DataFormatT:
"""Unicode escape
Args:
padding (int, optional): Optional padding. Defaults to 0.
uppercase_hex (bool, optional): Uppercase hex chars. Defaults to False.
Returns:
Chepy: The Chepy object.
"""

def unicode_replacer(match):
code_point = ord(match.group(0))
padding_format = "{:04x}".format(code_point)
if uppercase_hex:
padding_format = padding_format.upper()
return r"\u" + "0" * padding + padding_format

escaped_string = re.sub(
r"[^\x00-\x7F]", unicode_replacer, self._convert_to_str()
)
self.state = escaped_string
return self
1 change: 1 addition & 0 deletions chepy/modules/dataformat.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,4 @@ class DataFormat(ChepyCore):
def from_upside_down(self: DataFormatT, reverse: bool=False) -> DataFormatT: ...
def to_messagepack(self: DataFormatT) -> DataFormatT: ...
def from_messagepack(self: DataFormatT) -> DataFormatT: ...
def unicode_escape(self: DataFormatT, padding: int = 0, uppercase_hex:bool=False) -> DataFormatT: ...
8 changes: 6 additions & 2 deletions chepy/modules/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,14 +533,16 @@ def diff(
buffer: int = None,
colors: bool = False,
swap: bool = False,
only_changes: bool = False
):
"""Diff state with another state or buffer
Args:
state (int, optional): Index of state to compare against. Defaults to None.
buffer (int, optional): Index of buffer to compare against. Defaults to None.
colors (int, optional): Show colored diff. Defaults to False.
swap (int, optional): Swap the diff order. Defaults to False.
colors (bool, optional): Show colored diff. Defaults to False.
swap (bool, optional): Swap the diff order. Defaults to False.
only_changes (bool, optional): Return only changes. Defaults to False.
Raises:
TypeError: If both state and buffer is set to True.
Expand Down Expand Up @@ -583,6 +585,8 @@ def process_tag(tag, i1, i2, j1, j2) -> UtilsT: # pragma: no cover
else:
return "{-" + matcher.a[i1:i2] + "}"
if tag == "equal":
if only_changes:
return ''
return matcher.a[i1:i2]
if tag == "insert":
if colors:
Expand Down
2 changes: 1 addition & 1 deletion chepy/modules/utils.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class Utils(ChepyCore):
def escape_string(self: UtilsT) -> UtilsT: ...
def unescape_string(self: UtilsT) -> UtilsT: ...
def color_hex_to_rgb(self: UtilsT) -> UtilsT: ...
def diff(self: UtilsT, state: int=..., buffer: int=..., colors: bool=..., swap: bool=...) -> UtilsT: ...
def diff(self: UtilsT, state: int=..., buffer: int=..., colors: bool=False, swap: bool=False, only_changes: bool=False) -> UtilsT: ...
def pad(self: UtilsT, width: int, direction: Literal['left', 'right']=..., char: str=...) -> UtilsT: ...
def count(self: UtilsT) -> UtilsT: ...
def set(self: UtilsT) -> UtilsT: ...
Expand Down
7 changes: 7 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,3 +245,10 @@ def test_subsection():
).o
== b"he955a367a4c01f58118021054729c7fb54b5de94ell9cba467d60276777ce655337e060fa0aebfcc780o"
)


def test_callback():
def cb(data):
return data * 2

assert Chepy("abc").callback(cb).o == b"abcabc"
14 changes: 13 additions & 1 deletion tests/test_dataformat.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def test_to_decimal():

def test_from_decimal():
assert Chepy(12622).from_decimal().o == b"\xe3\x85\x8e"
assert Chepy('97-98-99').from_decimal().o == b"abc"
assert Chepy("97-98-99").from_decimal().o == b"abc"


def test_to_binary():
Expand Down Expand Up @@ -585,3 +585,15 @@ def test_messagepack():
assert Chepy("hello").to_messagepack().from_messagepack().o == b"hello"
assert Chepy(["hello"]).to_messagepack().from_messagepack().o == ["hello"]
assert Chepy({"a": "hello"}).to_messagepack().from_messagepack().o == {"a": "hello"}


def test_unicode_escape():
data = "MMMMM‌‍aaaaaaa‌‍ssss‌‌oooooonnnnnCCC‌‌CCCC"
assert (
Chepy(data).unicode_escape(padding=4, uppercase_hex=True).o
== b"MMMMM\u0000200C\u0000200Daaaaaaa\u0000200C\u0000200Dssss\u0000200C\u0000200CoooooonnnnnCCC\u0000200C\u0000200CCCCC"
)
assert (
Chepy(data).unicode_escape().o
== b"MMMMM\u200c\u200daaaaaaa\u200c\u200dssss\u200c\u200coooooonnnnnCCC\u200c\u200cCCCC"
)
1 change: 1 addition & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ def test_diff():
d.state += " hehe"
d.find_replace("lo", "").diff(state=1)
assert d.o == b"{a->A} {-lo}ng {s->S}entence {h->H}aha{+ hehe}"
assert Chepy("he", "she").diff(1, only_changes=True).o == b"{-s}"


def test_pad():
Expand Down

0 comments on commit 291f773

Please sign in to comment.