{
  "name": "Dispatcher (Hardened)",
  "nodes": [
    {
      "parameters": {
        "path": "reputation",
        "authentication": "basicAuth",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "e5ff4367-c475-4386-a265-ebe0f5452e1e",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -880,
        192
      ],
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Validate indicator format with strict regex\n// Only authenticated requests reach here (Basic Auth on Webhook)\n\nconst query = $input.first().json.query;\n\nconst patterns = {\n  ip:     /^(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$/,\n  domain: /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,63}$/,\n  hash:   /^[a-fA-F0-9]{32}(?:[a-fA-F0-9]{8})?(?:[a-fA-F0-9]{24})?(?:[a-fA-F0-9]{64})?$/,\n  cve:    /^CVE-\\d{4}-\\d{4,7}$/i\n};\n\nconst sanitized = {};\nlet matchedType = null;\n\nfor (const [type, regex] of Object.entries(patterns)) {\n  const value = query[type];\n  if (value !== undefined && value !== null && value !== '') {\n    let trimmed = String(value).trim();\n    // Security Onion sends CVE_YYYY_NNNNN \u2014 normalize underscores to hyphens\n    if (type === 'cve') { trimmed = trimmed.replace(/_/g, '-'); }\n    if (!regex.test(trimmed)) {\n      throw new Error(`Invalid ${type} format: rejected`);\n    }\n    sanitized[type] = trimmed;\n    matchedType = type;\n  }\n}\n\nif (!matchedType) {\n  throw new Error('No valid indicator parameter provided. Use: ip, domain, hash, or cve');\n}\n\nreturn [{ json: { query: sanitized } }];"
      },
      "id": "a1b2c3d4-0001-4000-8000-000000000001",
      "name": "Validate Input",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -640,
        192
      ]
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.query.ip }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "id": "57a58621-7277-4779-b4ca-c4e3784769a7"
                  }
                ],
                "combinator": "and"
              }
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "57704503-054c-4e89-9eb6-ee0022bf7f6e",
                    "leftValue": "={{ $json.query.domain }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              }
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "35b4bc37-1c97-4c25-96cf-2d7cc446cc44",
                    "leftValue": "={{ $json.query.hash }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              }
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "b0e84252-1ec8-4568-bdf9-7b6753d753ae",
                    "leftValue": "={{ $json.query.cve }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              }
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        -368,
        192
      ],
      "id": "03e92725-3f11-43e5-b654-c2ebc615b607",
      "name": "Route by Indicator Type"
    },
    {
      "parameters": {
        "workflowId": "hWWjpKVA93Gnzokc",
        "options": {}
      },
      "id": "8e9fd45f-f399-45a5-9454-f21fce036f91",
      "name": "IP Reputation",
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1,
      "position": [
        -48,
        -96
      ]
    },
    {
      "parameters": {
        "workflowId": "HZF3eyeWRivMxHmt",
        "options": {}
      },
      "id": "2180b5e5-5045-4323-aeaa-0d56f4bb2624",
      "name": "Domain Reputation",
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1,
      "position": [
        -48,
        96
      ]
    },
    {
      "parameters": {
        "workflowId": "F0mEuPeG51TxxbBy",
        "options": {}
      },
      "id": "ba3e5d77-7def-4c63-bf49-86c1246e2afe",
      "name": "Hash Reputation",
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1,
      "position": [
        -48,
        288
      ]
    },
    {
      "parameters": {
        "workflowId": "U6vW2CgBa47fgRTQ",
        "options": {}
      },
      "id": "a1b12110-5df2-4ad0-8b29-e2539c13bac1",
      "name": "CVE Info",
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1,
      "position": [
        -48,
        480
      ]
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ $json.html }}",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/html; charset=utf-8"
              },
              {
                "name": "X-Content-Type-Options",
                "value": "nosniff"
              }
            ]
          }
        }
      },
      "id": "7a919ffa-84e6-46f5-96c1-66360c3d56b6",
      "name": "Respond IP",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        336,
        -96
      ]
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ $json.html }}",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/html; charset=utf-8"
              },
              {
                "name": "X-Content-Type-Options",
                "value": "nosniff"
              }
            ]
          }
        }
      },
      "id": "2c9d161a-2e95-4719-b31d-7fb950befebd",
      "name": "Respond Domain",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        336,
        96
      ]
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ $json.html }}",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/html; charset=utf-8"
              },
              {
                "name": "X-Content-Type-Options",
                "value": "nosniff"
              }
            ]
          }
        }
      },
      "id": "7547984f-e701-4cf0-8323-abc2c99423ec",
      "name": "Respond Hash",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        336,
        288
      ]
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ $json.html }}",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/html; charset=utf-8"
              },
              {
                "name": "X-Content-Type-Options",
                "value": "nosniff"
              }
            ]
          }
        }
      },
      "id": "bb12c9aa-0d32-4168-9294-e582f2486f83",
      "name": "Respond CVE",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        336,
        480
      ]
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Error</title><link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/bulma@1.0.1/css/bulma.min.css\"><link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/bulma-prefers-dark@0.1.0/css/bulma-prefers-dark.min.css\"><style>@media(prefers-color-scheme:dark){html,body{background-color:hsl(0,0%,21%)}}</style></head><body><section class=\"hero is-fullheight\"><div class=\"hero-body\"><div class=\"container is-fluid content\"><p class=\"title is-3\">Invalid Request</p><p>No valid indicator parameter was matched. Supported parameters: <code>ip</code>, <code>domain</code>, <code>hash</code>, <code>cve</code>.</p></div></div><div class=\"hero-foot\"><footer class=\"footer\"><div class=\"content has-text-centered\"><p>ArkCybr SOC Dispatcher</p></div></footer></div></section></body></html>",
        "options": {
          "responseCode": 400,
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/html; charset=utf-8"
              },
              {
                "name": "X-Content-Type-Options",
                "value": "nosniff"
              }
            ]
          }
        }
      },
      "id": "a1b2c3d4-0002-4000-8000-000000000002",
      "name": "Respond Invalid Request",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        -48,
        672
      ]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Validate Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Input": {
      "main": [
        [
          {
            "node": "Route by Indicator Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Indicator Type": {
      "main": [
        [
          {
            "node": "IP Reputation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Domain Reputation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Hash Reputation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "CVE Info",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond Invalid Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IP Reputation": {
      "main": [
        [
          {
            "node": "Respond IP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Domain Reputation": {
      "main": [
        [
          {
            "node": "Respond Domain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hash Reputation": {
      "main": [
        [
          {
            "node": "Respond Hash",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CVE Info": {
      "main": [
        [
          {
            "node": "Respond CVE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}