Fixes to encode.py, requirements.txt and updated README.txt with encode commnds help
This commit is contained in:
@@ -390,7 +390,14 @@ A fully offline, CyberChef-like data manipulation plugin with dozens of operatio
|
||||
|
||||
**Compression**
|
||||
|
||||
`gzip`, `zlib`, `bzip2`, `lzma` — each supports `compress` and `decompress` subcommands.
|
||||
| Operation | Example |
|
||||
|-----------|---------|
|
||||
| `gzip compress\|decompress` | `!encode gzip compress "Hello World"` |
|
||||
| `zlib compress\|decompress` | `!encode zlib compress "Hello World"` |
|
||||
| `bzip2 compress\|decompress` | `!encode bzip2 compress "Hello World"` |
|
||||
| `lzma compress\|decompress` | `!encode lzma compress "Hello World"` |
|
||||
| `deflate compress\|decompress` | `!encode deflate compress "Hello World"` |
|
||||
| `zstd compress\|decompress` | `!encode zstd compress "Hello World"` |
|
||||
|
||||
**Data Processing**
|
||||
|
||||
@@ -430,6 +437,27 @@ A fully offline, CyberChef-like data manipulation plugin with dozens of operatio
|
||||
```
|
||||
!encode recipe list
|
||||
!encode recipe run '{"steps":[{"op":"base64","args":["encode"]},{"op":"hex","args":["encode"]}]}' "hello world"
|
||||
!encode recipe run 'base64 encode | hex encode :: hello world'
|
||||
```
|
||||
|
||||
**Recipe Commands Details:**
|
||||
- `!encode recipe list` - Lists all available operations that can be chained together
|
||||
- `!encode recipe run '<json>' <data>` - Execute a JSON recipe on input data
|
||||
- `!encode recipe run '<op> arg | <op> arg :: <data>'` - Execute a pipe-style recipe with data
|
||||
|
||||
JSON recipes allow complex operation chaining with the format:
|
||||
```json
|
||||
{
|
||||
"steps": [
|
||||
{"op": "base64", "args": ["encode"]},
|
||||
{"op": "hex", "args": ["encode"]}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Pipe-style recipes provide a simpler syntax:
|
||||
```
|
||||
base64 encode | hex encode :: hello world
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
+123
-11
@@ -55,6 +55,12 @@ try:
|
||||
except ImportError:
|
||||
HAS_CRYPTOGRAPHY = False
|
||||
|
||||
try:
|
||||
import zstandard
|
||||
HAS_ZSTD = True
|
||||
except ImportError:
|
||||
HAS_ZSTD = False
|
||||
|
||||
try:
|
||||
import bcrypt
|
||||
HAS_BCRYPT = True
|
||||
@@ -855,6 +861,46 @@ async def op_dns(text: str) -> str:
|
||||
except Exception as e:
|
||||
return f"DNS error: {e}"
|
||||
|
||||
@register_op("deflate", "Raw DEFLATE compress / decompress", "Compression", arg_names=["subcmd"])
|
||||
async def op_deflate(subcmd: str, text: str) -> str:
|
||||
sub = subcmd.lower()
|
||||
raw = validate_input(text)
|
||||
if sub in ("compress", "comp", "c"):
|
||||
# Use zlib in raw‑deflate mode (wbits=-15)
|
||||
compressor = zlib.compressobj(level=6, wbits=-15)
|
||||
compressed = compressor.compress(raw) + compressor.flush()
|
||||
return base64.b64encode(compressed).decode()
|
||||
elif sub in ("decompress", "decomp", "d"):
|
||||
try:
|
||||
decompressed = zlib.decompress(base64.b64decode(raw), wbits=-15)
|
||||
return decompressed.decode("utf-8", errors="replace")
|
||||
except Exception as e:
|
||||
return f"DEFLATE decompress error: {e}"
|
||||
else:
|
||||
raise ValueError("Use 'compress' or 'decompress'")
|
||||
|
||||
|
||||
@register_op("zstd", "Zstandard compress / decompress", "Compression", arg_names=["subcmd"])
|
||||
async def op_zstd(subcmd: str, text: str) -> str:
|
||||
if not HAS_ZSTD:
|
||||
return "Error: zstandard library not installed"
|
||||
import zstandard as zstd
|
||||
sub = subcmd.lower()
|
||||
raw = validate_input(text)
|
||||
if sub in ("compress", "comp", "c"):
|
||||
cctx = zstd.ZstdCompressor()
|
||||
compressed = cctx.compress(raw)
|
||||
return base64.b64encode(compressed).decode()
|
||||
elif sub in ("decompress", "decomp", "d"):
|
||||
try:
|
||||
dctx = zstd.ZstdDecompressor()
|
||||
decompressed = dctx.decompress(base64.b64decode(raw))
|
||||
return decompressed.decode("utf-8", errors="replace")
|
||||
except Exception as e:
|
||||
return f"Zstd decompress error: {e}"
|
||||
else:
|
||||
raise ValueError("Use 'compress' or 'decompress'")
|
||||
|
||||
# ---------- Recipe system ----------
|
||||
class Recipe:
|
||||
"""A sequence of operations to apply."""
|
||||
@@ -896,9 +942,9 @@ class Recipe:
|
||||
break
|
||||
return data
|
||||
|
||||
@register_op("recipe", "Run a recipe (provide JSON and data)", "Recipes",
|
||||
@register_op("recipe", "Run a recipe (JSON or pipe syntax)", "Recipes",
|
||||
arg_names=["subcmd"])
|
||||
async def op_recipe(subcmd: str, json_or_data: str, *extra: str) -> str:
|
||||
async def op_recipe(subcmd: str, json_or_data: str) -> str:
|
||||
sub = subcmd.lower()
|
||||
if sub == "list":
|
||||
cats = collections.defaultdict(list)
|
||||
@@ -908,20 +954,79 @@ async def op_recipe(subcmd: str, json_or_data: str, *extra: str) -> str:
|
||||
for cat in sorted(cats):
|
||||
out.append(f"{cat}: {', '.join(cats[cat])}")
|
||||
return "\n".join(out)
|
||||
|
||||
elif sub == "run":
|
||||
# Usage: !encode recipe run '<json>' <data>
|
||||
# Here json_or_data is the JSON string, extra[0] is the data
|
||||
if not extra:
|
||||
raise ValueError("Provide data after JSON recipe")
|
||||
recipe_json = json_or_data
|
||||
data = " ".join(extra) # extra is tuple
|
||||
s = json_or_data.strip()
|
||||
|
||||
# Strip a single pair of matching outer quotes if present
|
||||
if (s.startswith("'") and s.endswith("'")) or (s.startswith('"') and s.endswith('"')):
|
||||
s = s[1:-1].strip()
|
||||
|
||||
# ---- try JSON first ----
|
||||
if s.startswith("{"):
|
||||
# original JSON parsing
|
||||
depth = 0
|
||||
end = 0
|
||||
for i, ch in enumerate(s):
|
||||
if ch == "{":
|
||||
depth += 1
|
||||
elif ch == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
end = i
|
||||
break
|
||||
if depth != 0:
|
||||
raise ValueError("Unbalanced braces in JSON recipe")
|
||||
|
||||
recipe_json = s[:end+1]
|
||||
data_part = s[end+1:].strip()
|
||||
if not data_part:
|
||||
raise ValueError("No data provided after JSON recipe")
|
||||
|
||||
try:
|
||||
recipe = Recipe.from_json(recipe_json)
|
||||
return await recipe.run(data, OPERATIONS)
|
||||
return await recipe.run(data_part, OPERATIONS)
|
||||
except Exception as e:
|
||||
return f"Recipe error: {e}"
|
||||
|
||||
# ---- try pipe syntax: op args ... | op args ... :: data ----
|
||||
# Split into operations and data at the last occurrence of " :: "
|
||||
if " :: " in s:
|
||||
ops_section, data_part = s.rsplit(" :: ", 1)
|
||||
data_part = data_part.strip()
|
||||
else:
|
||||
raise ValueError("Use 'list' or 'run <json> <data>'")
|
||||
raise ValueError(
|
||||
"Pipe syntax: !encode recipe run <op> [args] | <op> [args] :: <data>\n"
|
||||
"Or JSON: !encode recipe run '{...}' <data>"
|
||||
)
|
||||
|
||||
ops_section = ops_section.strip()
|
||||
if not ops_section:
|
||||
raise ValueError("At least one operation is required before ::")
|
||||
if not data_part:
|
||||
raise ValueError("No data provided after ::")
|
||||
|
||||
# Split operations by " | "
|
||||
ops_parts = [p.strip() for p in ops_section.split(" | ")]
|
||||
steps = []
|
||||
for part in ops_parts:
|
||||
tokens = part.split()
|
||||
if not tokens:
|
||||
continue
|
||||
op_name = tokens[0].lower()
|
||||
if op_name not in OPERATIONS:
|
||||
raise ValueError(f"Unknown operation '{op_name}' in pipe recipe")
|
||||
args = tokens[1:] # remaining tokens are args
|
||||
steps.append({"op": op_name, "args": args})
|
||||
|
||||
try:
|
||||
recipe = Recipe(steps)
|
||||
return await recipe.run(data_part, OPERATIONS)
|
||||
except Exception as e:
|
||||
return f"Recipe error: {e}"
|
||||
|
||||
else:
|
||||
raise ValueError("Use 'list' or 'run'")
|
||||
|
||||
# ---------- Main handler (interface to the bot) ----------
|
||||
async def handle_command(room, message, bot, prefix, config):
|
||||
@@ -1137,6 +1242,10 @@ compression, data processing, forensics, and networking. Fully offline.
|
||||
<code>!encode bzip2 compress data</code></li>
|
||||
<li><b>lzma</b> – LZMA compress/decompress<br>
|
||||
<code>!encode lzma compress data</code></li>
|
||||
<li><b>deflate</b> – Raw DEFLATE compress/decompress<br>
|
||||
<code>!encode deflate compress data</code></li>
|
||||
<li><b>zstd</b> – Zstandard compress/decompress (requires zstandard)<br>
|
||||
<code>!encode zstd compress data</code></li>
|
||||
</ul>
|
||||
|
||||
<h3>Data Processing</h3>
|
||||
@@ -1195,7 +1304,10 @@ compression, data processing, forensics, and networking. Fully offline.
|
||||
<li><b>recipe list</b> – List all available operations<br>
|
||||
<code>!encode recipe list</code></li>
|
||||
<li><b>recipe run</b> – Execute a JSON recipe on data<br>
|
||||
<code>!encode recipe run '{"steps":[{"op":"base64","args":["encode"]},{"op":"hex","args":["encode"]}]}' "hello world"</code></li>
|
||||
<code>!encode recipe run '{"steps":[{"op":"base64", args ["encode"]}, {"op":"hex", args ["encode"]}]}' "hello world"</code></li>
|
||||
<li><b>recipe run (pipe syntax)</b> – Chain operations with <code>|</code> and separate data with <code>::</code><br>
|
||||
<code>!encode recipe run base64 encode | hex encode :: hello world</code><br>
|
||||
<code>!encode recipe run base64 encode | hex encode | gzip compress :: my secret data</code></li>
|
||||
</ul>
|
||||
|
||||
<p>Type <code>!encode help <op></code> for detailed argument info on any operation.</p>
|
||||
|
||||
@@ -23,3 +23,4 @@ PyYAML
|
||||
wcwidth
|
||||
markdown
|
||||
python-cryptography-fernet-wrapper
|
||||
zstandard
|
||||
Reference in New Issue
Block a user