{
  "name": "CyberShield Universal Workflow v4",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "ejecutar-ataque",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "cs-webhook",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        240,
        400
      ]
    },
    {
      "parameters": {
        "operation": "find",
        "collection": "attack-templates",
        "query": "={{ JSON.stringify({ name: $json.body.task_name || $json.task_name || 'unknown' }) }}",
        "limit": 1,
        "options": {}
      },
      "id": "cs-mongo-find",
      "name": "MongoDB",
      "type": "n8n-nodes-base.mongoDb",
      "typeVersion": 1.1,
      "position": [
        480,
        400
      ],
      "credentials": {
        "mongoDb": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// ============================================================\n// CONSTRUIR COMANDO desde la plantilla de MongoDB + params del usuario\n// ============================================================\n// MongoDB devuelve la plantilla con command_base y params por defecto.\n// El webhook envia los params del usuario que sobreescriben los defaults.\n// Este nodo fusiona ambos y reemplaza los {{placeholders}}.\n// ============================================================\n\nconst mongoResult = $input.first().json;\nconst webhookData = $('Webhook').first().json;\nconst body = webhookData.body || webhookData;\n\nconst taskName = body.task_name || 'unknown';\nconst userParams = body.params || {};\nconst ts = Date.now();\n\n// Si MongoDB devolvio plantilla, usarla; si no, fallback\nlet commandBase = '';\nlet templateParams = {};\nlet postNotify = '';\nlet mitreId = 'N/A';\nlet severity = 'medium';\n\nif (mongoResult && mongoResult.command_base) {\n  commandBase = mongoResult.command_base;\n  templateParams = mongoResult.params || {};\n  postNotify = mongoResult.post_attack_notify || '';\n  mitreId = mongoResult.mitre_id || 'N/A';\n  severity = mongoResult.severity || 'medium';\n} else {\n  // FALLBACK: si no hay plantilla en MongoDB para este ataque\n  commandBase = 'echo \"Ataque no encontrado en MongoDB: ' + taskName + '\"';\n}\n\n// Fusionar params: defaults de MongoDB + overrides del usuario\nconst mergedParams = Object.assign({}, templateParams, userParams);\nmergedParams.timestamp = String(ts);\n\n// Reemplazar todos los {{placeholder}} en el comando\nlet command = commandBase;\nfor (const [key, value] of Object.entries(mergedParams)) {\n  const regex = new RegExp('\\\\{\\\\{' + key + '\\\\}\\\\}', 'g');\n  command = command.replace(regex, String(value));\n}\n\n// Construir el post_attack_notify (logger para Wazuh)\nlet loggerCmd = postNotify;\nfor (const [key, value] of Object.entries(mergedParams)) {\n  const regex = new RegExp('\\\\{\\\\{' + key + '\\\\}\\\\}', 'g');\n  loggerCmd = loggerCmd.replace(regex, String(value));\n}\n\n// Encadenar: comando del ataque + logger para Wazuh\nconst fullCommand = loggerCmd\n  ? command + '; ' + loggerCmd\n  : command;\n\nreturn [{\n  json: {\n    command: fullCommand,\n    task_name: taskName,\n    params: mergedParams,\n    mitre_id: mitreId,\n    severity: severity,\n    timestamp: ts,\n    started_at: new Date().toISOString()\n  }\n}];"
      },
      "id": "cs-build-cmd",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        400
      ]
    },
    {
      "parameters": {
        "command": "={{ $json.command }}"
      },
      "id": "cs-ssh-exec",
      "name": "Execute a command",
      "type": "n8n-nodes-base.ssh",
      "typeVersion": 1,
      "position": [
        960,
        400
      ],
      "credentials": {
        "sshPassword": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Post-procesado: recoger output y preparar datos para informe PDF\nconst ssh = $input.first().json;\nconst prev = $('Code in JavaScript').first().json;\nconst stdout = ssh.stdout || '';\nconst stderr = ssh.stderr || '';\nconst exitCode = ssh.exitCode || 0;\nconst durationSec = Math.round((Date.now() - new Date(prev.started_at).getTime()) / 1000);\n\nreturn [{\n  json: {\n    task_name: prev.task_name,\n    params: prev.params,\n    mitre_id: prev.mitre_id,\n    severity: prev.severity,\n    timestamp: prev.timestamp,\n    started_at: prev.started_at,\n    finished_at: new Date().toISOString(),\n    duration_seconds: durationSec,\n    output: stdout,\n    stderr: stderr,\n    exit_code: exitCode,\n    success: exitCode === 0,\n    xml_output: stdout.includes('<?xml') ? stdout : '',\n    target: prev.params.target || prev.params.bssid || prev.params.interface || 'N/A',\n    scan_target: prev.params.target || 'N/A'\n  }\n}];"
      },
      "id": "cs-post-process",
      "name": "Post-Procesado",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1200,
        400
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://host.docker.internal:3010/generate-attack-report",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json) }}",
        "options": {
          "timeout": 30000
        }
      },
      "id": "cs-gen-report",
      "name": "Generar Informe PDF",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1440,
        400
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ ok: true, task_name: $('Post-Procesado').first().json.task_name, success: $('Post-Procesado').first().json.success, exit_code: $('Post-Procesado').first().json.exit_code, output_preview: ($('Post-Procesado').first().json.output || '').slice(0, 500), duration: $('Post-Procesado').first().json.duration_seconds, timestamp: new Date().toISOString() }) }}",
        "options": {}
      },
      "id": "cs-respond",
      "name": "Responder Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1680,
        400
      ]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "MongoDB",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "MongoDB": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Execute a command",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute a command": {
      "main": [
        [
          {
            "node": "Post-Procesado",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post-Procesado": {
      "main": [
        [
          {
            "node": "Generar Informe PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generar Informe PDF": {
      "main": [
        [
          {
            "node": "Responder Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true
  },
  "triggerCount": 1
}