Files
Bjorn/actions/demo_action.py

235 lines
7.4 KiB
Python

# demo_action.py
# Demonstration Action: wrapped in a DemoAction class
# ---------------------------------------------------------------------------
# Metadata (compatible with sync_actions / Neo launcher)
# ---------------------------------------------------------------------------
b_class = "DemoAction"
b_module = "demo_action"
b_enabled = 1
b_action = "normal" # normal | aggressive | stealth
b_category = "demo"
b_name = "Demo Action"
b_description = "Demonstration action: simply prints the received arguments."
b_author = "Template"
b_version = "0.1.0"
b_icon = "demo_action.png"
b_examples = [
{
"profile": "quick",
"interface": "auto",
"target": "192.168.1.10",
"port": 80,
"protocol": "tcp",
"verbose": True,
"timeout": 30,
"concurrency": 2,
"notes": "Quick HTTP scan"
},
{
"profile": "deep",
"interface": "eth0",
"target": "example.org",
"port": 443,
"protocol": "tcp",
"verbose": False,
"timeout": 120,
"concurrency": 8,
"notes": "Deep TLS profile"
}
]
b_docs_url = "docs/actions/DemoAction.md"
# ---------------------------------------------------------------------------
# UI argument schema
# ---------------------------------------------------------------------------
b_args = {
"profile": {
"type": "select",
"label": "Profile",
"choices": ["quick", "balanced", "deep"],
"default": "balanced",
"help": "Choose a profile: speed vs depth."
},
"interface": {
"type": "select",
"label": "Network Interface",
"choices": [],
"default": "auto",
"help": "'auto' tries to detect the default network interface."
},
"target": {
"type": "text",
"label": "Target (IP/Host)",
"default": "192.168.1.1",
"placeholder": "e.g. 192.168.1.10 or example.org",
"help": "Main target."
},
"port": {
"type": "number",
"label": "Port",
"min": 1,
"max": 65535,
"step": 1,
"default": 80
},
"protocol": {
"type": "select",
"label": "Protocol",
"choices": ["tcp", "udp"],
"default": "tcp"
},
"verbose": {
"type": "checkbox",
"label": "Verbose output",
"default": False
},
"timeout": {
"type": "slider",
"label": "Timeout (seconds)",
"min": 5,
"max": 600,
"step": 5,
"default": 60
},
"concurrency": {
"type": "range",
"label": "Concurrency",
"min": 1,
"max": 32,
"step": 1,
"default": 4,
"help": "Number of parallel tasks (demo only)."
},
"notes": {
"type": "text",
"label": "Notes",
"default": "",
"placeholder": "Free-form comments",
"help": "Free text field to demonstrate a simple string input."
}
}
# ---------------------------------------------------------------------------
# Dynamic detection of interfaces
# ---------------------------------------------------------------------------
import os
try:
import psutil
except Exception:
psutil = None
def _list_net_ifaces() -> list[str]:
names = set()
if psutil:
try:
names.update(ifname for ifname in psutil.net_if_addrs().keys() if ifname != "lo")
except Exception:
pass
try:
for n in os.listdir("/sys/class/net"):
if n and n != "lo":
names.add(n)
except Exception:
pass
out = ["auto"] + sorted(names)
seen, unique = set(), []
for x in out:
if x not in seen:
unique.append(x)
seen.add(x)
return unique
def compute_dynamic_b_args(base: dict) -> dict:
d = dict(base or {})
if "interface" in d:
d["interface"]["choices"] = _list_net_ifaces() or ["auto", "eth0", "wlan0"]
if d["interface"].get("default") not in d["interface"]["choices"]:
d["interface"]["default"] = "auto"
return d
# ---------------------------------------------------------------------------
# DemoAction class
# ---------------------------------------------------------------------------
import argparse
class DemoAction:
"""Wrapper called by the orchestrator."""
def __init__(self, shared_data):
self.shared_data = shared_data
self.meta = {
"class": b_class,
"module": b_module,
"enabled": b_enabled,
"action": b_action,
"category": b_category,
"name": b_name,
"description": b_description,
"author": b_author,
"version": b_version,
"icon": b_icon,
"examples": b_examples,
"docs_url": b_docs_url,
"args_schema": b_args,
}
def execute(self, ip=None, port=None, row=None, status_key=None):
"""Called by the orchestrator. This demo only prints arguments."""
self.shared_data.bjorn_orch_status = "DemoAction"
self.shared_data.comment_params = {"ip": ip, "port": port}
print("=== DemoAction :: executed ===")
print(f" IP/Target: {ip}:{port}")
print(f" Row: {row}")
print(f" Status key: {status_key}")
print("No real action performed: demonstration only.")
return "success"
def run(self, argv=None):
"""Standalone CLI mode for testing."""
parser = argparse.ArgumentParser(description=b_description)
parser.add_argument("--profile", choices=b_args["profile"]["choices"],
default=b_args["profile"]["default"])
parser.add_argument("--interface", default=b_args["interface"]["default"])
parser.add_argument("--target", default=b_args["target"]["default"])
parser.add_argument("--port", type=int, default=b_args["port"]["default"])
parser.add_argument("--protocol", choices=b_args["protocol"]["choices"],
default=b_args["protocol"]["default"])
parser.add_argument("--verbose", action="store_true",
default=bool(b_args["verbose"]["default"]))
parser.add_argument("--timeout", type=int, default=b_args["timeout"]["default"])
parser.add_argument("--concurrency", type=int, default=b_args["concurrency"]["default"])
parser.add_argument("--notes", default=b_args["notes"]["default"])
args = parser.parse_args(argv)
print("=== DemoAction :: received parameters ===")
for k, v in vars(args).items():
print(f" {k:11}: {v}")
print("\n=== Demo usage of parameters ===")
if args.verbose:
print("[verbose] Verbose mode enabled → simulated detailed logs...")
if args.profile == "quick":
print("Profile: quick → would perform fast operations.")
elif args.profile == "deep":
print("Profile: deep → would perform longer, more thorough operations.")
else:
print("Profile: balanced → compromise between speed and depth.")
print(f"Target: {args.target}:{args.port}/{args.protocol} via {args.interface}")
print(f"Timeout: {args.timeout} sec, Concurrency: {args.concurrency}")
print("No real action performed: demonstration only.")
if __name__ == "__main__":
DemoAction(shared_data=None).run()