Recorded Login: Trails service documentation

The service that runs Recorded Login recordings is called Trails. If you for some reason need to modify your .trail files containing your recordings, please refer to this documentation.


For most use cases, you will not need to refer to this documentation to troubleshoot or solve any issues you might experience while setting up your Recorded Login. For a general introduction and troubleshooting tips to this functionality, read more about how to scan behind login using Recorded Login.

Background

Trails is a way for Detectify to reach the logged-in state of your web application in order to perform an authenticated scan. The entire service is based around a JSON specification containing various actions. An action could be, "move the mouse cursor", "click on an element" or "enter some text in an input/textarea".

 

By performing these events, various requests will be made. These requests are recorded for future use. Any cookie being set will be used elsewhere later when performing crawling and security testing.


Our plugin can also be used to record the Recorded Crawling user flows that can be uploaded in your Scan Settings. Read more about how to use Recorded Crawling


Description

The data format is a JSON document containing two arrays of actions. The actions define how we are to interact with the site. The first set of arrays is called the "Commands"-node. Everything defined therein will run the first time the trail is executed. The second node is called "SanityChecks". Like with "Commands", this node contain a set of actions. The difference is that "SanityChecks" will run after all "Commands" are done (and Detectify have reached the assumed state), and then once more per minute indefinitely. The reason for this behavior is to validate that we are still authenticated or otherwise have reached the correct state in the application. If any assertion fail, then we assume the state is lost from "Commands", and the entire process will restart and "Commands" will run again in an attempt to regain the state.


The entire document should be considered a checklist. On the first execution all action nodes stored in "Commands" will be executed. A failure to execute an action (or if an assertion fails) will terminate the chain of commands and the trail should be considered failed. If all "Commands" execute successfully the trail is working. When the trail reaches a working state the "SanityChecks" will run sequentially in a similar manner as of "Commands". If the "SanityChecks" fail (either by a failed action or by assertion), the entire chain of "Commands" will have to re-run to reach the same initial state again. The "SanityChecks" should run in a loop to constantly verify that the correct states are reached.


Example file

Note: There are JavaScript comments in this file, so it may or may not be serializable to proper JSON.

{
  "Type": "Recording",
  "Version": "5.0",
  "CreationDate": "2022-12-21",
  "CreatedInIncognito": true,
  "PluginVersion": "4.3",
  "Name": "example.com-detectify-recording",

  // Run this to reach a given state (i.e, authenticate as a user)
  "Commands": [
    {
      "type": "UserAction",
      "version": "1.0",
      "command": "setViewport",
      "selectors": [],
      "values": [
        "2488",
        "1340"
      ]
    },
    {
      "type": "Selenium",
      "version": "1.0",
      "command": "open",
      "selectors": [],
      "values": [
        "https://example.com/login/"
      ]
    },
    {
      "type": "UserAction",
      "version": "1.0",
      "command": "input",
      "selectors": [
        [
          "css=body > form > input[type=\"text\"]:nth-child(1)"
        ],
        [
          "css=[type='text']"
        ],
        [
          "css=input:nth-of-type(1)"
        ],
        [
          "css=input[type='text']"
        ]
      ],
      "values": [
        "admin"
      ]
    },
    {
      "type": "UserAction",
      "version": "1.0",
      "command": "input",
      "selectors": [
        [
          "css=body > form > input[type=\"password\"]:nth-child(2)"
        ],
        [
          "css=[type='password']"
        ],
        [
          "css=input:nth-of-type(2)"
        ],
        [
          "css=input[type='password']"
        ]
      ],
      "values": [
        "password"
      ]
    },
    {
      "type": "UserAction",
      "version": "1.0",
      "command": "mouseClick",
      "selectors": [
        [
          "css=body > form > button"
        ],
        [
          "css=button"
        ]
      ],
      "values": []
    },
    {
      "type": "Helper",
      "version": "1.0",
      "command": "sleep",
      "selectors": [],
      "values": [
        "5000"
      ]
    },
    {
      "type": "Extractor",
      "version": "1.0",
      "command": "defaults",
      "selectors": [],
      "values": []
    }
  ],

   // Will run sequentially in a loop once per minute, if the assertion fails re-run "Commands"
  "SanityChecks": [
    {
      "type": "Selenium",
      "version": "1.0",
      "command": "verifyElementPresent",
      "selectors": [
        [
          "text=logout"
        ]
      ],
      "values": []
    },
    {
      "type": "Selenium",
      "version": "1.0",
      "command": "verifyURL",
      "selectors": [],
      "values": [
        "glob:http://example.com/login/"
      ]
    }
  ]
}