UNPKG

@neuralegion/nextemplate

Version:

Template parser library used for dynamic values interpolation in [Bright DAST app](https://app.brightsec.com).

317 lines (211 loc) 8.07 kB
# nextemplate Template parser library used for dynamic values interpolation in [Bright DAST app](https://app.brightsec.com). ## Template syntax The template syntax in `nextemplate` utilizes double curly braces `{{` and `}}` as delimiters for interpolation expressions. Two types of interpolation expressions are supported within these curly braces: **variable** expressions and **yield** expressions (prefixed with `$`). ### Variable expressions > ⚠️ Variable expressions must be prefixed with a context name. Currently, the only supported contexts are `auth_object` and `entrypoint`. Additional supported contexts may be added in the future. > ⚠️ Each context currently has a limited set of supported references. Under the `auth_object` context, you can currently use stage references and OTP token references. Under the `entrypoint` context, currently only parameter references are supported. #### Stage references Example: `{{ auth_object.stages.custom_stage_name1.response.body }}` A stage reference consists of the following components: - context (`auth_object`) - special word (`stages`) - stage name: - any word (\w), number (\d) or underscore characters - or special `any` literal - source (`request` or `response`) - location in the source (`url`, `headers`, or `body`). For data transformation, a pipe operator (`|`) is available, supporting parameters and chaining. Example: `{{ auth_object.stages.custom_stage_name1.response.headers | get: '/Set-Cookie' | match: /sid=(.+)/ : 1 }}` #### OTP token references Example: `{{ auth_object.otps.custom_otp_token_name1 }}` OTP token references do not support nested references. The pipes are supported, e.g.: `{{ auth_object.otps.custom_otp_token_name1 | match: /^.{1}(.)/ : 1 }}` #### Entrypoint parameters references Example: `{{ entrypoint.params.some_param_name }}` A parameter name should start with a letter and can be followed by letters, digits, and underscores. Entrypoint parameters references do not support nested references or pipes. ### Yield expressions > ⚠️ Yield expressions other than $faker could be supported in the future, but currently parser will produce an error. #### $faker references Example: `{{ $faker.datatype.uuid }}` Inspired by [@faker-js/faker](https://www.npmjs.com/package/@faker-js/faker). The first part is predefined `$faker` literal, the second part - faker dataset name (`datatype` is single supported atm), the third - function name from given dataset (ony `uuid` and `number` are supported). ### Supported pipes #### get Returns the value associated with the XPath, or undefined if there is none. _Format_: `{{ stage_reference | get : xpath }}` _Parameters_: - `xpath` - xpath string _Example_: `{{ auth_object.stages.custom_stage_name1.response.headers | get: '/Set-Cookie' }}` #### match Retrieves the result of matching a string against a regular expression. _Format_: `{{ stage_reference | match : regexp : group }}` _Parameters_: - `regexp` - regular expression, - `group` - number of the capture group (optional, default 1) _Example_: `{{ auth_object.stages.custom_stage_name1.response.body | match: /sid=(.+)/ : 1 }}` #### encode Encodes the value to some format. _Format_: `{{ stage_reference | encode : format }}` _Parameters_: - `format ` - `base64`, `url`, `html` or `none` (optional, default `none`) _Example_: `{{ auth_object.stages.custom_stage_name1.response.body | encode: 'base64' }}` #### decode Decodes the value from some format. _Format_: `{{ stage_reference | decode : format }}` _Parameters_: - `format ` - `base64`, `url`, `html` or `none` (optional, default `none`) _Example_: `{{ auth_object.stages.custom_stage_name1.response.body | decode: 'base64' }}` ## Install 🚀 `npm i --save @neuralegion/nextemplate` ## API Main parser function: `parse(template: string): ParseResult` Auxiliary `faker`-like generator that consumes generation template (like `faker.datatype.uuid`) as string or `source` from `ParsedFakerExpression` from parser output: `fakerFn(fakerTemplate: string | { source: string } & any): string` where ```ts type ParseResult = (string | ParsedOtpTokenExpression | ParsedStageVariableExpression | ParsedFakerExpression)[]; interface ParsedExpression { type: 'variable' | 'yield'; source: string; raw: string; } interface ParsedVariableExpression extends ParsedExpression { context: 'auth_object' | 'entrypoint'; type: 'variable'; } interface ParsedOtpTokenExpression extends ParsedVariableExpression { context: 'auth_object'; } interface ParsedStageVariableExpression extends ParsedVariableExpression { context: 'auth_object'; pipes: ParsedPipe[]; } interface ParsedEntrypointParamsVariableExpression extends ParsedVariableExpression { context: 'entrypoint'; source: 'params'; name: string; } interface ParsedPipe { name: 'get' | 'match' | 'encode' | 'decode; args: (string | number)[]; } interface ParsedYieldExpression extends ParsedExpression { type: 'yield'; value: string; } interface ParsedFakerExpression extends ParsedYieldExpression { } ``` ## Sample output #### Input template string `prefix {{ auth_object.stages.custom_stage_name1.response.headers | get : '/Set-Cookie' | match : /sid=(.+)/ | encode : 'base64' }} {{ $faker.datatype.uuid }} {{ auth_object.otps.custom_otp_token_name1 }} {{ entrypoint.params.some_param_name }} suffix` #### Parser output ```json [ "prefix ", { "context": "auth_object", "type": "variable", "source": "stages.custom_stage_name1.response.headers", "pipes": [ { "name": "get", "args": ["/Set-Cookie"] }, { "name": "match", "args": ["/sid=(.+)/", 1] }, { "name": "encode", "args": ["base64"] } ], "raw": "{{ auth_object.stages.custom_stage_name1.response.headers | get : '/Set-Cookie' | match : /sid=(.+)/ | encode : 'base64' }}" }, " ", { "type": "yield", "source": "faker.datatype.uuid", "value": "c6c27519-acb4-4875-91d9-298b921b5104", "raw": "{{ $faker.datatype.uuid }}" }, " ", { "context": "auth_object", "type": "variable", "source": "otps.custom_otp_token_name1", "pipes": [], "raw": "{{ auth_object.otps.custom_otp_token_name1 }}" }, " ", { "context": "entrypoint", "type": "variable", "source": "params", "name": "some_param_name", "raw": "{{ entrypoint.params.some_param_name }}" }, " suffix" ] ``` #### fakerFn usage examples ``` > fakerFn('faker.datatype.uuid') 48b0504d-b146-40f7-8fc2-fe19b7b9dc7b > fakerFn({ source: 'faker.datatype.uuid' })` b81b54de-735f-401d-aa77-ebd69d4293c2 ``` ## Usage <details> <summary>ECMAScript 2015, Typescript modules</summary> ``` import { parse } from '@neuralegion/nextemplate'; console.log(parse('some_template')); ``` </details> <details> <summary>NodeJS (CommonJS module)</summary> ``` const parser = require('@neuralegion/nextemplate'); console.log(parser.parse('some_template')); ``` </details> <details> <summary>NodeJS (experimental ESM support)</summary> `usage.mjs` file: ``` import parser from '@neuralegion/nextemplate'; console.log(parser.parse('some_template')); ``` Running: `node --experimental-modules ./usage.mjs` </details> <details> <summary>Browser (globals from umd bundle)</summary> ``` <script src="./node_modules/@neuralegion/nextemplate/dist/bundle.umd.js"></script> <script> alert(nextemplate.parse('some_template')); </script> ``` </details> <details> <summary>Browser (ES modules)</summary> ``` <script type="module"> import { parse } from './node_modules/@neuralegion/nextemplate/dist/bundle.es.js'; alert(parse('some_template')); </script> ``` </details> ## Development 🛠 Issues and pull requests are highly welcome. 👍 Please, don't forget to lint (`npm run lint`) and test (`npm t`) the code. ## License Copyright © 2023 [Bright Security](https://brightsec.com). This project is licensed under the MIT License - see the [LICENSE file](LICENSE) for details.