Demo.Plugins.GUI

A demo plugin showing some GUI features.

This plugin is also used for tests.


name: Demo.Plugins.GUI
description: |
  A demo plugin showing some GUI features.

  This plugin is also used for tests.

resources:
  timeout: 20
  ops_per_second: 60
  max_rows: 213
  max_upload_bytes: 545454

parameters:
  - name: ChoiceSelector
    description: Choose one item from a selection
    type: choices
    default: First Choice
    choices:
      - First Choice
      - Second Choice
      - Third Choice

  - name: MultiChoiceSelector
    description: Choose one or more items from a selection
    type: multichoice
    default: '["Bananas"]'
    choices:
      - Apples
      - Bananas
      - Oranges
      - Grapes

  - name: Hashes
    validating_regex: '^\s*([A-F0-9]+\s*)+$'
    description: One or more hashes in hex separated by white space.

  - name: RegularExpression
    type: regex
    default: "."

  - name: MultipleRegularExpression
    type: regex_array
    default: '[".+"]'

  - name: YaraRule
    type: yara

  - name: Flag
    friendly_name: A Flag with a name
    type: bool
    default: True

  - name: Flag2
    type: bool
    default: Y

  - name: Flag3
    type: bool
    default: Y

  - name: OffFlag
    type: bool

  - name: StartDate
    type: timestamp

  - name: StartDate2
    type: timestamp

  - name: StartDate3
    type: timestamp

  - name: CSVData
    type: csv
    default: |
      Column1,Column2
      A,B
      C,D

  - name: CSVData2
    type: csv
    default: |
      Column1,Column2
      A,B
      C,D

  - name: JSONData
    type: json_array
    default: "[]"

  - name: JSONData2
    type: json_array
    default: |
      [{"foo": "bar"}]

  - name: FileUpload1
    type: upload
    description: FileUpload1 can receive a file upload. The upload content will be available in this variable when executing on the client.

  - name: ArtifactSelections
    type: artifactset
    description: A selection of artifact
    artifact_type: CLIENT_EVENT
    default: |
      Artifact
      Windows.Detection.PsexecService
      Windows.Events.ProcessCreation
      Windows.Events.ServiceCreation

column_types:
  - name: Base64Hex
    type: base64hex

sources:
  - query: |
      SELECT base64encode(string="This should popup in a hex editor") AS Base64Hex,
             ChoiceSelector, MultiChoiceSelector, Flag, Flag2, Flag3,
             OffFlag, StartDate, StartDate2, StartDate3,
             CSVData, CSVData2, JSONData, JSONData2,
             len(list=FileUpload1) AS FileUpload1Length
      FROM scope()

    notebook:
      - type: vql_suggestion
        name: Test Suggestion
        template: |
          /*
          # This is a suggestion notebook cell.

          It should be available from the suggestions list.
          */
          SELECT * FROM info()

      - type: md
        template: |
          # GUI Notebook tests

          The following cells are testing the notebook in the flow. To
          run this test simply collect the `Demo.Plugins.GUI` artifact
          and check the output is correct.

          **Each of the below cells should have a H2 heading**

          ## Check that notebook environment variables are populated
          {{ $x := Query "SELECT * FROM items(\
             item=dict(NotebookId=NotebookId, ClientId=ClientId,\
                       FlowId=FlowId, ArtifactName=ArtifactName))" | Expand }}

          {{ range $x }}
          * {{ Get . "_key" }} - {{ Get . "_value" }}
          {{- end -}}

      - type: md
        template: |
          ## Code syntax highlighting for VQL

          ```vql
          SELECT * FROM info()
          ```

      - type: vql
        template: |
          /*
          ## A VQL cell with a heading.
          */
          LET ColumnTypes = dict(
            Time1="timestamp",
            Time2="timestamp",
            Time3="timestamp",
            Time4="timestamp",
            FlowId="flow",
            ClientId="client",
            Data="hex",
            URL="url",
            SafeURL="safe_url", // Present dialog before click.
            Base64Data="base64hex"
          )

          LET Base64Data = base64encode(string="\x00\x01\x20\x32\x12\x10")
          LET URL = "[Google](https://www.google.com)"

          SELECT 1628609690.1 AS Raw,

                 -- float
                 1628609690.1 AS Time1,

                 -- ms as a string
                 "1628609690100" AS Time2,

                 -- ns
                 1628609690100000 AS Time3,

                 -- Standard string form
                 "2021-08-10T15:34:50Z" AS Time4,

                 FlowId, ClientId, URL, URL AS SafeURL, Base64Data,

                 format(format="%02x", args="Hello") AS Data,
                 TRUE, 4, NULL
          FROM scope()

      - type: Markdown
        template: |
          ## Scatter Chart with a named column

          {{ define "ScatterTest" }}
           SELECT X, Name, Y, Y3
          FROM parse_csv(accessor="data", filename='''
          X,Name,Y,Y3
          1,Bob,2,3
          2,Frank,4,6
          3,Mike,6,8
          4,Sally,3,2
           ''')
          {{ end }}
          {{ Query "ScatterTest" | ScatterChart "name_column" "Name" }}

          ## Stacked Bar Chart (Categories are first column)

          {{ define "Test" }}
          SELECT X, Y, Y3
          FROM parse_csv(accessor="data", filename='''
          X,Y,Y3
          Bob,2,3
          Bill,4,6
          Foo,6,8
          Bar,7,2
          ''')
          {{ end }}
          {{ Query "Test" | BarChart "type" "stacked" }}

          ## Time chart with timestamp in first column

          {{ define "TimeTest" }}
          SELECT Timestamp, Y, Y3
          FROM parse_csv(accessor="data", filename='''
          Timestamp,Y,Y3
          2021-10-09,2,3
          2021-10-10,4,6
          2021-10-11,6,8
          2021-10-12,7,2
          ''')
          {{ end }}
          {{ Query "TimeTest" | TimeChart }}

          ## Line chart

          {{ define "LineTest" }}
          SELECT X, Y, Y3
          FROM parse_csv(accessor="data", filename='''
          X,Y,Y3
          1,2,3
          2,4,6
          3,6,8
          4,7,2
          ''')
          {{ end }}
          {{ Query "LineTest" | LineChart }}

      - type: Markdown
        template: |
          ## A Line Chart

          The following should show a CPU load chart of the last 10 min.

          {{ define "Q" }}
            SELECT _ts, CPUPercent
            FROM monitoring(
                  client_id="server",
                  artifact="Server.Monitor.Health/Prometheus",
                  start_time=now() - 10 * 60)
            LIMIT 100
          {{ end }}

          {{ Query "Q" | TimeChart }}

      - type: vql
        template: |
          /*
          ## Adding timelines

          Add a timeline from this time series data. (This only works
          for root org because it relies on server health events).

          */
          SELECT timestamp(epoch=_ts) AS Timestamp, CPUPercent
          FROM monitoring(
            client_id="server",
            source="Prometheus",
            artifact="Server.Monitor.Health",
            start_time=now() - 10 * 60)

          LET T1 = SELECT
               timestamp(epoch=_ts) AS Timestamp,
               dict(X=CPUPercent, Y=1) AS Dict
          FROM monitoring(
            client_id="server",
            source="Prometheus",
            artifact="Server.Monitor.Health",
            start_time=now() - 10 * 60)

          -- Add the time series into the timeline.
          SELECT timeline_add(
              key="Timestamp", name="Time 你好世界 'line' &\" ",
              query=T1, timeline="Test \"Timeline 你好世界\""),
           timeline_add(
              key="Timestamp", name="2",
              query=T1, timeline="Test \"Timeline 你好世界\"")
          FROM scope()

      - type: Markdown
        env:
          - key: Timeline
            value: Test "Timeline 你好世界"
        template: |
          ## This super timeline should have two timelines.

          Add a timeline manually and hit refresh on this cell to
          check it is being updated.

          {{ Scope "Timeline" | Timeline }}

      - type: VQL
        template: |
          /*
          # Test table scrolling.

          Check both expanded and contracted states of the cell
          */
          LET zalgo = "1̴̣̜̗̰͇͖͖̞̮͈͍̂͜.̸̢̧̨͙̻̜̰̼̔̿̓̄̀̅͌̈́͒͗̈́̒̕̚͜͠e̶̙̞̬̹̥͖̤̟͑͒̂̀̔͠x̵̛̱̠̳͍̦̘̤̙͚̙͈̬́̈́͂̎̽̇̀͝ę̵̯̦̫͖͖͍͈̟̠͉̥͒̑̐̏̕̚̕͜͠"
          LET Test = "Hellothereongline" + zalgo

          SELECT Test AS Test1, Test AS Test2, Test AS Test3,
                 Test AS Test4, Test AS Test5,
                 Test AS Test11, Test AS Test21,
                 Test AS Test13, Test AS Test14, Test AS Test15,
                 Test AS Test21, Test AS Test22,
                 Test AS Test23, Test AS Test24, Test AS Test25
          FROM range(start=0, end=100, step=1)

      - type: VQL
        template: |
          /*
          # Column types set in the artifact's `column_types` field

          These apply to notebooks automatically without needing to
          define them again.

          * Hash column should right click to VT
          * upload preview should show the uploaded file.

          */

          LET ColumnTypes = dict(`StartDate`='timestamp', Download='download',
                                 Hex='hex', Upload='preview_upload')
          LET Hex = "B0 EC 48 5F 18 77"

          SELECT Hex, StartDate, hash(accessor="data", path="Hello") AS Hash,
                 upload(accessor="data", file="Hello world",
                        name="test.txt") AS Upload,
                 upload(accessor="data", file="Hello world",
                        name="test.txt") AS Download
          FROM source()

      - type: VQL
        template: |
          /* Test the JSON renderer. */
          LET Strings = SELECT "Hello World" AS A FROM range(end=100)

          LET MultiColumn = SELECT * FROM chain(a={
            SELECT 1 AS A FROM range(end=10)
          }, b={
            SELECT 1 AS B FROM range(end=10)
          })

          SELECT dict(
            MultiColumn=MultiColumn,
            Strings=Strings.A,
            `NULL`=NULL,
            Bool=TRUE,
            BoolF=FALSE,
            BinaryData=base64encode(string="hello world"),
            Rows={
              SELECT count() AS Count,
                     rand() AS R
              FROM range(end=20)
            },
            Integer=1, Float=1.235,
            LongString="Hello world " * 100,
            MixedList=[1, 2, dict(A=3)],
            NestedDict=dict(
                Foo=dict(A=1,
                         B=dict(z=1,
                                nesting=dict(Foo="Hello world"))))) AS A
          FROM scope()

      - type: VQL
        template: |
          /*
          # Test the link_to() VQL Function
          */
          LET ColumnTypes <= dict(
            LinkToFlow="url_internal",
            LinkToHunt="url_internal",
            LinkToArtifact="url_internal",
            Download="url_internal",
            LinkToClient="url_internal")

          LET s = scope()
          LET Uploaded <= upload(accessor="data", file="Hello", name="test.txt")

          SELECT link_to(client_id=ClientId, flow_id=s.FlowId || "F.123") AS LinkToFlow,
                 link_to(client_id=ClientId) AS LinkToClient,
                 link_to(hunt_id=s.HuntId || "H.123") AS LinkToHunt,
                 link_to(artifact=ArtifactName) AS LinkToArtifact,
                 link_to(upload=Uploaded) AS Download
          FROM scope()