---
description: Pipeline for parsing Anomali Limo indicators
processors:
  ####################
  # Event ECS fields #
  ####################
  - set:
      field: event.ingested
      value: "{{_ingest.timestamp}}"
  - set:
      field: event.kind
      value: enrichment
  - set:
      field: event.category
      value: threat
  - set:
      field: event.type
      value: indicator

  ######################
  # General ECS fields #
  ######################
  - rename:
      field: message
      target_field: event.original
      ignore_missing: true
      if: ctx.event?.original == null
  - json:
      field: event.original
      target_field: anomali.limo
  - fingerprint:
      fields:
        - anomali.limo.id
      target_field: "_id"
      ignore_missing: true

  #####################
  # Threat ECS Fields #
  #####################
  - set:
      field: threat.feed.name
      value: "[Filebeat] Anomali Limo"
  - set:
      field: threat.feed.dashboard_id
      value: "ad9c7430-72de-11eb-a3e3-b3cc7c78a70f"
  ## File indicator operations
  - date:
      field: anomali.limo.created
      formats:
        - "yyyy-MM-dd'T'HH:mm:ssz"
        - "yyyy-MM-dd'T'HH:mm:ssZ"
        - "yyyy-MM-dd'T'HH:mm:ss.Sz"
        - "yyyy-MM-dd'T'HH:mm:ss.SZ"
        - "yyyy-MM-dd'T'HH:mm:ss.SSz"
        - "yyyy-MM-dd'T'HH:mm:ss.SSZ"
        - "yyyy-MM-dd'T'HH:mm:ss.SSSz"
        - "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
      if: "ctx.anomali?.limo?.created != null"
  - date:
      field: anomali.limo.modified
      target_field: anomali.limo.modified
      formats:
        - "yyyy-MM-dd'T'HH:mm:ssz"
        - "yyyy-MM-dd'T'HH:mm:ssZ"
        - "yyyy-MM-dd'T'HH:mm:ss.Sz"
        - "yyyy-MM-dd'T'HH:mm:ss.SZ"
        - "yyyy-MM-dd'T'HH:mm:ss.SSz"
        - "yyyy-MM-dd'T'HH:mm:ss.SSZ"
        - "yyyy-MM-dd'T'HH:mm:ss.SSSz"
        - "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
      if: "ctx.anomali?.limo?.modified != null"
  - date:
      field: anomali.limo.valid_from
      target_field: threat.indicator.first_seen
      formats:
        - "yyyy-MM-dd'T'HH:mm:ssz"
        - "yyyy-MM-dd'T'HH:mm:ssZ"
        - "yyyy-MM-dd'T'HH:mm:ss.Sz"
        - "yyyy-MM-dd'T'HH:mm:ss.SZ"
        - "yyyy-MM-dd'T'HH:mm:ss.SSz"
        - "yyyy-MM-dd'T'HH:mm:ss.SSZ"
        - "yyyy-MM-dd'T'HH:mm:ss.SSSz"
        - "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
      if: "ctx.anomali?.limo?.valid_from != null"
  - grok:
      field: anomali.limo.pattern
      patterns:
        - "^\\[%{DATA:_tmp.threattype}:value%{SPACE}=%{SPACE}'%{DATA:_tmp.threatvalue}'\\]"
      if: ctx.anomali?.limo?.pattern != null
  - rename:
      field: _tmp.threattype
      target_field: threat.indicator.type
      ignore_missing: true
  - rename:
      field: _tmp.threatvalue
      target_field: threat.indicator.ip
      ignore_missing: true
      if: "['ipv4-addr', 'ipv6-addr'].contains(ctx.threat?.indicator?.type)"
  - uri_parts:
      field: _tmp.threatvalue
      target_field: threat.indicator.url
      keep_original: true
      remove_if_successful: true
      if: ctx.threat?.indicator?.type == 'url'
  - set:
      field: threat.indicator.url.full
      value: "{{{threat.indicator.url.original}}}"
      ignore_empty_value: true
  - rename:
      field: _tmp.threatvalue
      target_field: threat.indicator.email.address
      ignore_missing: true
      if: ctx.threat?.indicator?.type == 'email-addr'
  - rename:
      field: _tmp.threatvalue
      target_field: threat.indicator.url.domain
      ignore_missing: true
      if: ctx.threat?.indicator?.type == 'domain-name'
  - set:
      field: threat.indicator.type
      value: unknown
      if: ctx.threat?.indicator?.type == null
  - foreach:
      field: anomali.limo.labels
      ignore_missing: true
      processor:
        append:
          field: tags
          value: "{{_ingest._value}}"
          allow_duplicates: false
  - grok:
      field: anomali.limo.description
      patterns:
        - "^%{GREEDYDATA}Source: %{GREEDYDATA:threat.indicator.provider}"
      ignore_missing: true
      ignore_failure: true
  ######################
  # Cleanup processors #
  ######################
  - script:
      lang: painless
      if: ctx?.threatintel != null
      source: |
        void handleMap(Map map) {
          for (def x : map.values()) {
            if (x instanceof Map) {
                handleMap(x);
            } else if (x instanceof List) {
                handleList(x);
            }
          }
        map.values().removeIf(v -> v == null);
        }
        void handleList(List list) {
          for (def x : list) {
              if (x instanceof Map) {
                  handleMap(x);
              } else if (x instanceof List) {
                  handleList(x);
              }
          }
        }
        handleMap(ctx);
  - remove:
      field: event.original
      if: "ctx?.tags == null || !(ctx.tags.contains('preserve_original_event'))"
      ignore_failure: true
      ignore_missing: true
  - remove:
      field:
        - anomali.limo.created
        - message
        - _tmp
      ignore_missing: true
on_failure:
  - set:
      field: error.message
      value: "{{ _ingest.on_failure_message }}"
