Extiende HexProxy con workspaces, hooks, exporters, analyzers y settings propios.
El sistema de plugins de HexProxy está pensado para equipos que necesitan adaptar el proxy a su operación real. Los plugins son módulos Python cargados dentro del proceso y pueden observar, transformar, enriquecer y exportar tráfico, además de inyectar componentes visuales y acciones dentro de la TUI.
Trusted Python modulesregister(api) / register() / PLUGIN / contribute(api)HookContext y PluginRenderContextMetadata persistente por flow
Arranque recomendado
HexProxy carga plugins Python desde la carpeta plugins/ y desde cada directorio adicional pasado con --plugin-dir. La recomendación práctica es comenzar con un plugin pequeño, validar que el runtime lo carga y recién después sumar panels, exporters o analyzers más complejos.
Los plugins son módulos Python de confianza cargados in-process. No hay sandbox, unload ni hot reload.
Loading model y entrypoints soportados
HexProxy recorre archivos *.py, ignora los que empiezan con guion bajo y acepta cuatro formas de entrada: register(api), register(), PLUGIN y contribute(api). Si un módulo expone register(api) o register() y devuelve None, el runtime conserva el propio módulo como instancia del plugin. Además, si existen tanto contribute(api) a nivel módulo como en la instancia, ambas contribuciones pueden ejecutarse.
def register(api):
return MyPlugin()
def contribute(api):
api.add_workspace(
"demo_workspace",
"Demo",
"Workspace del módulo"
)
Clases y contextos principales
La API v2 gira en torno a dos contextos. HookContext vive dentro del pipeline de tráfico y permite etiquetar, persistir metadata, anexar findings y acceder a estado global o de proyecto. PluginRenderContext vive en renderers, exporters, analyzers, metadata providers, keybindings y callbacks de settings, y ofrece acceso al entry seleccionado, request, response, store, TUI y helpers de estado.
context.set_metadata("jwt_inspector", "summary", json.dumps(summary))
context.add_finding("jwt_inspector", "JWT observado en request")
def render_panel(context):
entry = context.entry
if entry is None:
return ["No flow selected."]
return [f"id={entry.id}"]
Hooks del runtime
Los hooks opcionales del plugin son on_loaded(), before_request_forward(...), on_response_received(...) y on_error(...). El hook de request corre después de la interceptación y antes del Match/Replace de request. El hook de response corre después de la respuesta upstream y antes del Match/Replace de response. Si necesitas alterar la respuesta, debes mutar el objeto en sitio; devolver otro response no tiene efecto contractual en el runtime actual.
Hook
Cuándo corre
Retorno
Uso típico
on_loaded()
Al terminar la carga del plugin
Ignorado
Inicialización simple
before_request_forward(context, request)
Antes del upstream request
ParsedRequest o None
Modificar headers, body o tags
on_response_received(context, request, response)
Después de recibir la respuesta
Ignorado
Persistir metadata, findings o mutar response in-place
Cuando el plugin usa register(api), recibe una instancia de PluginAPI. Desde ahí puede registrar workspaces, panels, exporters, keybindings, analyzers, metadata providers y campos dentro de Settings. En la práctica, esa es la superficie principal para extender la UI y el flujo operativo.
Crea un workspace superior nuevo. El workspace_id debe ser único y no puede colisionar con workspaces built-in como overview, intercept, repeater, http o settings.
Registra panels dentro de workspaces propios o sobre targets internos como overview_detail, http_request, http_response, sitemap_request, sitemap_response, repeater_request y repeater_response.
Registra acciones configurables por teclado. Las keys deben tener uno o dos caracteres visibles. El runtime rechaza whitespace, duplicados y prefijos ambiguos como d coexistiendo con dw.
add_analyzer(...) y add_metadata(...)
Permiten producir findings y colecciones estructuradas visibles dentro de la TUI. Son ideales para plugins que inspeccionan JWT, headers de seguridad, tokens o patrones repetitivos.
Agrega campos a Settings. Los kind soportados son toggle, choice, text y action. El scope puede ser global o project.
Código de ejemplo visible en la página
Aquí tienes ejemplos completos y listos para copiar. El primero muestra un plugin mínimo que crea un workspace y un panel. El segundo muestra una inspección básica que persiste metadata JSON-safe y findings por flow.
def render_export(context):
entry = context.entry
if entry is None:
export_source = getattr(context, "export_source", None)
entry_id = getattr(export_source, "entry_id", None)
if entry_id is not None:
entry = context.store.get(entry_id)
if entry is None:
return "No flow available."
bucket = entry.plugin_metadata.get("example_inspector", {})
return json.dumps(bucket, indent=2, ensure_ascii=False)
Pitfalls y comportamiento real del runtime
La trampa principal del sistema actual es que HookContext.metadata persiste todo como string. Si guardas dicts o listas sin serializarlos, luego los panels fallarán al intentar tratarlos como estructuras reales. El patrón seguro es json.dumps(...) al escribir y json.loads(...) al leer. También conviene tratar export_source como un objeto dinámico y usar getattr(...) de forma defensiva.