Fixes to encode.py, requirements.txt and updated README.txt with encode commnds help

This commit is contained in:
2026-05-10 11:02:35 -05:00
parent a1ce95f72f
commit 15cf9e72bb
3 changed files with 154 additions and 13 deletions
+29 -1
View File
@@ -390,7 +390,14 @@ A fully offline, CyberChef-like data manipulation plugin with dozens of operatio
**Compression** **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** **Data Processing**
@@ -430,6 +437,27 @@ A fully offline, CyberChef-like data manipulation plugin with dozens of operatio
``` ```
!encode recipe list !encode recipe list
!encode recipe run '{"steps":[{"op":"base64","args":["encode"]},{"op":"hex","args":["encode"]}]}' "hello world" !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
``` ```
--- ---
+124 -12
View File
@@ -55,6 +55,12 @@ try:
except ImportError: except ImportError:
HAS_CRYPTOGRAPHY = False HAS_CRYPTOGRAPHY = False
try:
import zstandard
HAS_ZSTD = True
except ImportError:
HAS_ZSTD = False
try: try:
import bcrypt import bcrypt
HAS_BCRYPT = True HAS_BCRYPT = True
@@ -855,6 +861,46 @@ async def op_dns(text: str) -> str:
except Exception as e: except Exception as e:
return f"DNS error: {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 rawdeflate 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 ---------- # ---------- Recipe system ----------
class Recipe: class Recipe:
"""A sequence of operations to apply.""" """A sequence of operations to apply."""
@@ -896,9 +942,9 @@ class Recipe:
break break
return data 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"]) 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() sub = subcmd.lower()
if sub == "list": if sub == "list":
cats = collections.defaultdict(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): for cat in sorted(cats):
out.append(f"{cat}: {', '.join(cats[cat])}") out.append(f"{cat}: {', '.join(cats[cat])}")
return "\n".join(out) return "\n".join(out)
elif sub == "run": elif sub == "run":
# Usage: !encode recipe run '<json>' <data> s = json_or_data.strip()
# Here json_or_data is the JSON string, extra[0] is the data
if not extra: # Strip a single pair of matching outer quotes if present
raise ValueError("Provide data after JSON recipe") if (s.startswith("'") and s.endswith("'")) or (s.startswith('"') and s.endswith('"')):
recipe_json = json_or_data s = s[1:-1].strip()
data = " ".join(extra) # extra is tuple
# ---- 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_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(
"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: try:
recipe = Recipe.from_json(recipe_json) recipe = Recipe(steps)
return await recipe.run(data, OPERATIONS) return await recipe.run(data_part, OPERATIONS)
except Exception as e: except Exception as e:
return f"Recipe error: {e}" return f"Recipe error: {e}"
else: else:
raise ValueError("Use 'list' or 'run <json> <data>'") raise ValueError("Use 'list' or 'run'")
# ---------- Main handler (interface to the bot) ---------- # ---------- Main handler (interface to the bot) ----------
async def handle_command(room, message, bot, prefix, config): 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> <code>!encode bzip2 compress data</code></li>
<li><b>lzma</b> LZMA compress/decompress<br> <li><b>lzma</b> LZMA compress/decompress<br>
<code>!encode lzma compress data</code></li> <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> </ul>
<h3>Data Processing</h3> <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> <li><b>recipe list</b> List all available operations<br>
<code>!encode recipe list</code></li> <code>!encode recipe list</code></li>
<li><b>recipe run</b> Execute a JSON recipe on data<br> <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> </ul>
<p>Type <code>!encode help &lt;op&gt;</code> for detailed argument info on any operation.</p> <p>Type <code>!encode help &lt;op&gt;</code> for detailed argument info on any operation.</p>
+1
View File
@@ -23,3 +23,4 @@ PyYAML
wcwidth wcwidth
markdown markdown
python-cryptography-fernet-wrapper python-cryptography-fernet-wrapper
zstandard