/**
Copyright: 2024 Contrast Security, Inc
  Contact: support@contrastsecurity.com
  License: Commercial

  NOTICE: This Software and the patented inventions embodied within may only be
  used as part of Contrast Security’s commercial offerings. Even though it is
  made available through public repositories, use of this Software is subject to
  the applicable End User Licensing Agreement found at
  https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
  between Contrast Security and the End User. The Software may not be reverse
  engineered, modified, repackaged, sold, redistributed or otherwise used in a
  way not consistent with the End User License Agreement.
*/
'use strict';

const { coerce } = require('semver');

/**
 * Values and data structures share among modules.
 * @module lib/rules/protect/common
 */

const ACTIONS = {
  CREATION: 'CREATION',
  PROPAGATION: 'PROPAGATION',
  TRIGGER: 'TRIGGER',
  TAG: 'TAG',
  A2A: 'A2A',
  A2P: 'A2P',
  A2O: 'A2O',
  A2R: 'A2R',
  O2A: 'O2A',
  O2P: 'O2P',
  O2O: 'O2O',
  O2R: 'O2R',
  P2A: 'P2A',
  P2P: 'P2P',
  P2O: 'P2O',
  P2R: 'P2R'
};

const ASSESS_STACKTRACES = {
  UNDEFINED: 'UNDEFINED',
  ALL: 'ALL',
  SOME: 'SOME',
  NONE: 'NONE'
};

const AUTHENTICATION = {
  UNAUTHENTICATED: 'UNAUTHENTICATED', // no login detected and no existing authenticated id found
  AUTHENTICATED: 'AUTHENTICATED', // no login detected but existing authenticated id found
  LOGIN_FAIL: 'LOGIN_FAIL', // login attempt apparently failed
  LOGIN_SUCCESS: 'LOGIN_SUCCESS', // login attempt apparently succeeded
  LOGIN_UNKNOWN: 'LOGIN_UNKNOWN' // login attempt but could not determine success
};

const SAFE_XSS_CONTENT_TYPES = [
  '/json',
  '/x-json',
  '/javascript',
  '/x-javascript',
  '/pdf',
  '/csv'
];

const DEBUG_LOG_LEVELS = {
  TRACE: 'TRACE',
  DEBUG: 'DEBUG',
  INFO: 'INFO',
  WARN: 'WARN',
  ERROR: 'ERROR'
};

const HTTP_EVENTS = {
  SERVER_CREATE: 'http.createServer',
  SERVER_LISTEN: 'http.Server.listen'
};

const INSTRUMENTATION_MODE = {
  UNDEFINED: 'UNDEFINED',
  AGENT_CONFIG: 'AGENT_CONFIG',
  DUPLEX: 'DUPLEX',
  PROFILER: 'PROFILER'
};

const RULE_TYPES = {
  DATAFLOW: 'dataflow',
  NON_DATAFLOW: 'nonDataflow'
};

const PROTECT_RULE_DEFINITION_TYPES = {
  KEYWORD: 'KEYWORD',
  PATTERN: 'PATTERN'
};

const EVENT_TYPES = {
  METHOD: 'METHOD',
  TAG: 'TAG',
  PROPAGATION: 'PROPAGATION'
};

const RULES = {
  BOT_BLOCKER: 'bot-blocker',
  CMD_INJECTION: 'cmd-injection',
  CMD_INJECTION_COMMAND_BACKDOORS: 'cmd-injection-command-backdoors',
  CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS:
    'cmd-injection-semantic-chained-commands',
  CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS:
    'cmd-injection-semantic-dangerous-paths',
  IP_DENYLIST: 'ip-denylist',
  METHOD_TAMPERING: 'method-tampering',
  // The following is not a known rule in TS and is only used by SR when
  // reporting certain analysis results. We convert to nosqli before reporting
  NOSQL_EXPANSION: 'nosql-expansion',
  NOSQL_INJECTION: 'nosql-injection',
  PATH_TRAVERSAL: 'path-traversal',
  REFLECTED_XSS: 'reflected-xss',
  SQL_INJECTION: 'sql-injection',
  SSJS_INJECTION: 'ssjs-injection',
  VIRTUAL_PATCH: 'virtual-patch',
  UNTRUSTED_DESERIALIZATION: 'untrusted-deserialization',
  UNSAFE_FILE_UPLOAD: 'unsafe-file-upload',
  XXE: 'xxe'
};

const CMD_INJECTION_SEMANTIC_TYPES = {
  CHAINING: 0,
  BACKDOOR: 1,
  PATH_ARGUMENT: 2
};

/**
 * Specifies the level of importance of an input evaluation. */
const IMPORTANCE = {
  /** Not important
   *  All of these are true of the assessment:
   *    1. Did not meet any threshold levels
   *    2. Matched only LOW or MEDIUM-scoring rules, if any  */
  NONE: 'NONE',

  /** Worth-watching
   *  All of these are true of the assessment:
   *    1. Met or exceeded a lower-set threshold marking significance
   *    2. Matched only LOW or MEDIUM-scoring rules  */
  WORTH_WATCHING: 'WORTH_WATCHING',

  /** Definite:
   *    1. Matched at least a single HIGH or CRITICAL-scoring rule */
  DEFINITE: 'DEFINITE'
};

const THRESHOLDS = {
  WATCH: 'WATCH',
  DEFINITE: 'DEFINITE'
};

/**
 * These are all possible scoring values an attack-detecting rule may have. */
const SCORES = {
  NONE: 'NONE',
  LOW: 'LOW',
  MEDIUM: 'MEDIUM',
  HIGH: 'HIGH',
  CRITICAL: 'CRITICAL'
};

/**
 * Each of the SCORES has an associated weight. The values are used to
 * identify whether an evaluation assessment has reached any numeric
 * threshold levels. */
const WEIGHTS = {
  NONE: 0,
  LOW: 1,
  MEDIUM: 2,
  HIGH: 3,
  CRITICAL: 4
};

const IMPACTS = {
  NONE: 0,
  LOW: 1,
  MEDIUM: 2,
  HIGH: 3,
  CRITICAL: 4
};

const EXCLUSION_TYPES = {
  URL: 'URL',
  INPUT: 'INPUT',
  CODE: 'CODE'
};

const EXCLUSION_MATCH_STRATEGIES = {
  ALL: 'ALL',
  ONLY: 'ONLY'
};

const EXCLUSION_INPUT_TYPES = {
  UNDEFINED: 'UNDEFINED',
  BODY: 'BODY',
  COOKIE: 'COOKIE',
  HEADER: 'HEADER',
  PARAMETER: 'PARAMETER',
  QUERYSTRING: 'QUERYSTRING'
};

const INPUT_TYPES = {
  UNDEFINED_TYPE: 'UNDEFINED_TYPE',
  BODY: 'BODY',
  COOKIE_NAME: 'COOKIE_NAME',
  COOKIE_VALUE: 'COOKIE_VALUE',
  DWR_VALUE: 'DWR_VALUE',
  GENERIC_XML: 'GENERIC_XML',
  IP: 'IP',
  HEADER: 'HEADER',
  JSON_VALUE: 'JSON_VALUE',
  JSON_ARRAYED_VALUE: 'JSON_ARRAYED_VALUE',
  METHOD: 'METHOD',
  MULTIPART_CONTENT_TYPE: 'MULTIPART_CONTENT_TYPE',
  MULTIPART_FIELD_NAME: 'MULTIPART_FIELD_NAME',
  MULTIPART_NAME: 'MULTIPART_NAME',
  MULTIPART_VALUE: 'MULTIPART_VALUE',
  PARAMETER_NAME: 'PARAMETER_NAME',
  PARAMETER_VALUE: 'PARAMETER_VALUE',
  QUERYSTRING: 'QUERYSTRING',
  REQUEST: 'REQUEST',
  SOCKET: 'SOCKET',
  XML_VALUE: 'XML_VALUE',
  URI: 'URI',
  URL: 'URL',
  URL_PARAMETER: 'URL_PARAMETER',
  UNKNOWN: 'UNKNOWN'
};

const INPUT_TYPES_WITH_PARAMS = {
  BODY: 'BODY',
  JSON_VALUE: 'JSON_VALUE',
  JSON_ARRAYED_VALUE: 'JSON_ARRAYED_VALUE',
  MULTIPART_VALUE: 'MULTIPART_VALUE',
  PARAMETER_VALUE: 'PARAMETER_VALUE',
  QUERYSTRING: 'QUERYSTRING',
  XML_VALUE: 'XML_VALUE',
  URI: 'URI',
  URL: 'URL'
};

const DOCUMENT_TYPES = {
  NORMAL: 'NORMAL',
  JSON: 'JSON',
  XML: 'XML'
};

const HTTP_VERBS = {
  GET: 'GET',
  HEAD: 'HEAD',
  POST: 'POST',
  PUT: 'PUT',
  DELETE: 'DELETE',
  CONNECT: 'CONNECT',
  OPTIONS: 'OPTIONS',
  TRACE: 'TRACE',
  PATCH: 'PATCH'
};

const LC_HTTP_VERBS = Object.keys(HTTP_VERBS).map((k) =>
  HTTP_VERBS[k].toLowerCase()
);

const PROTOCOLS = {
  FTP: 'FTP',
  HTTP: 'HTTP',
  HTTPS: 'HTTPS',
  TCP: 'TCP'
};

const SINK_TYPES = {
  CODE_ENV: Symbol('CODE_ENV'),
  CODE_STRING: Symbol('CODE_STRING'),
  COMMAND: Symbol('COMMAND'),
  DESERIALIZED_STRING: Symbol('DESERIALIZED_STRING'),
  FILE_PATH: Symbol('PATH'),
  NOSQL_QUERY: Symbol('NOSQL_QUERY'),
  RESPONSE_BODY: Symbol('BODY'),
  RESPONSE_HEADERS: Symbol('HEADERS'),
  RESPONSE_STATUS: Symbol('STATUS'),
  SQL_QUERY: Symbol('QUERY'),
  XML_STRING: Symbol('XML_STRING')
};

const CONNECTION_TYPES = {
  UNENCRYPTED: 'UNENCRYPTED',
  ENCRYPTED: 'ENCRYPTED'
};

const PROTECTION_MODES = {
  NO_ACTION: 'NO_ACTION',
  MONITOR: 'MONITOR',
  BLOCK: 'BLOCK',
  BLOCK_AT_PERIMETER: 'BLOCK_AT_PERIMETER',
  PERMIT: 'PERMIT'
};

const PROTECT_RULE_SUPPORTED_MODES = {
  [RULES.BOT_BLOCKER]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.BLOCK_AT_PERIMETER
  ],
  [RULES.CMD_INJECTION]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK,
    PROTECTION_MODES.BLOCK_AT_PERIMETER
  ],
  [RULES.CMD_INJECTION_COMMAND_BACKDOORS]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK
  ],
  [RULES.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK
  ],
  [RULES.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK
  ],
  [RULES.IP_DENYLIST]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.BLOCK_AT_PERIMETER
  ],
  [RULES.METHOD_TAMPERING]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK,
    PROTECTION_MODES.BLOCK_AT_PERIMETER
  ],
  [RULES.NOSQL_INJECTION]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK,
    PROTECTION_MODES.BLOCK_AT_PERIMETER
  ],
  [RULES.PATH_TRAVERSAL]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK,
    PROTECTION_MODES.BLOCK_AT_PERIMETER
  ],
  [RULES.REFLECTED_XSS]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK,
    PROTECTION_MODES.BLOCK_AT_PERIMETER
  ],
  [RULES.SQL_INJECTION]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK,
    PROTECTION_MODES.BLOCK_AT_PERIMETER
  ],
  [RULES.SSJS_INJECTION]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK,
    PROTECTION_MODES.BLOCK_AT_PERIMETER
  ],
  [RULES.VIRTUAL_PATCH]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK_AT_PERIMETER
  ],
  [RULES.UNSAFE_FILE_UPLOAD]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK_AT_PERIMETER
  ],
  [RULES.XXE]: [
    PROTECTION_MODES.NO_ACTION,
    PROTECTION_MODES.MONITOR,
    PROTECTION_MODES.BLOCK
  ]
};

const REACTION_OPERATION = {
  NOOP: 'NOOP',
  DISABLE: 'DISABLE',
  INVENTORY: 'INVENTORY'
};

const SYSLOG_SEVERITIES = {
  UNDEFINED: 'UNDEFINED',
  ALERT: 'ALERT',
  CRITICAL: 'CRITICAL',
  ERROR: 'ERROR',
  WARNING: 'WARNING',
  NOTICE: 'NOTICE',
  INFO: 'INFO',
  DEBUG: 'DEBUG'
};

const ATTACK_STATUS = {
  BLOCKED: 'blocked',
  BLOCKED_AT_PERIMETER: 'blockedAtPerimeter',
  EXPLOITED: 'exploited',
  INEFFECTIVE: 'ineffective'
};

const WORD_SHARE = {
  COMMA: ',',
  FORWARD_SLASH: '/',
  SPACE: ' '
};

/**
 * Copied from EventTagTypeDTM
 */
const TAGS = {
  'xml-encoded': 'XML_ENCODED',
  'xml-decoded': 'XML_DECODED',
  'html-encoded': 'HTML_ENCODED',
  'html-decoded': 'HTML_DECODED',
  'url-encoded': 'URL_ENCODED',
  'url-decoded': 'URL_DECODED',
  'css-encoded': 'CSS_ENCODED',
  'css-decoded': 'CSS_DECODED',
  'base64-encoded': 'BASE64_ENCODED',
  'base64-decoded': 'BASE64_DECODED',
  'javascript-encoded': 'JAVASCRIPT_ENCODED',
  'javascript-decoded': 'JAVASCRIPT_DECODED',
  'java-encoded': 'JAVA_ENCODED',
  'java-decoded': 'JAVA_DECODED',
  'csv-encoded': 'CSV_ENCODED',
  'csv-decoded': 'CSV_DECODED',
  'sql-encoded': 'SQL_ENCODED',
  'sql-decoded': 'SQL_DECODED',
  'ldap-encoded': 'LDAP_ENCODED',
  'ldap-decoded': 'LDAP_DECODED',
  'xpath-encoded': 'XPATH_ENCODED',
  'xpath-decoded': 'XPATH_DECODED',
  'os-encoded': 'OS_ENCODED',
  'os-decoded': 'OS_DECODED',
  'vbscript-encoded': 'VBSCRIPT_ENCODED',
  'vbscript-decoded': 'VBSCRIPT_DECODED',
  'potential-sanitized': 'POTENTIAL_SANITIZED',
  'potential-validated': 'POTENTIAL_VALIDATED',
  'no-control-chars': 'NO_CONTROL_CHARS',

  // default catch all
  'custom-catch-all': 'CUSTOM',

  // custom encoded/validated tags, only for data flow rules
  'custom-encoded': 'CUSTOM_ENCODED',
  'custom-encoded-cmd-injection': 'CUSTOM_ENCODED_CMD_INJECTION',
  'custom-encoded-expression-language-injection':
    'CUSTOM_ENCODED_EXPRESSION_LANGUAGE_INJECTION',
  'custom-encoded-header-injection': 'CUSTOM_ENCODED_HEADER_INJECTION',
  'custom-encoded-hql-injection': 'CUSTOM_ENCODED_HQL_INJECTION',
  'custom-encoded-ldap-injection': 'CUSTOM_ENCODED_LDAP_INJECTION',
  'custom-encoded-log-injection': 'CUSTOM_ENCODED_LOG_INJECTION',
  'custom-encoded-nosql-injection': 'CUSTOM_ENCODED_NOSQL_INJECTIOn',
  'custom-encoded-path-traversal': 'CUSTOM_ENCODED_PATH_TRAVERSAL',
  'custom-encoded-redos': 'CUSTOM_ENCODED_REDOS',
  'custom-encoded-reflected-xss': 'CUSTOM_ENCODED_REFLECTED_XSS',
  'custom-encoded-reflection-injection': 'CUSTOM_ENCODED_REFLECTION_INJECTION',
  'custom-encoded-smtp-injection': 'CUSTOM_ENCODED_SMTP_INJECTION',
  'custom-encoded-sql-injection': 'CUSTOM_ENCODED_SQL_INJECTION',
  'custom-encoded-ssrf': 'CUSTOM_ENCODED_SSRF',
  'custom-encoded-stored-xss': 'CUSTOM_ENCODED_STORED_XSS',
  'custom-encoded-trust-boundary-violation':
    'CUSTOM_ENCODED_TRUST_BOUNDARY_VIOLATION',
  'custom-encoded-unsafe-code-execution':
    'CUSTOM_ENCODED_UNSAFE_CODE_EXECUTION',
  'custom-encoded-unsafe-readline': 'CUSTOM_ENCODED_UNSAFE_READLINE',
  'custom-encoded-unsafe-xml-decode': 'CUSTOM_ENCODED_UNSAFE_XML_DECODE',
  'custom-encoded-untrusted-deserialization':
    'CUSTOM_ENCODED_UNTRUSTED_DESERIALIZATION',
  'custom-encoded-unvalidated-forward': 'CUSTOM_ENCODED_UNVALIDATED_FORWARD',
  'custom-encoded-unvalidated-redirect': 'CUSTOM_ENCODED_UNVALIDATED_REDIRECT',
  'custom-encoded-xpath-injection': 'CUSTOM_ENCODED_XPATH_INJECTION',
  'custom-encoded-xxe': 'CUSTOM_ENCODED_XXE',
  'custom-security-control-applied': 'CUSTOM_SECURITY_CONTROL_APPLIED',

  'custom-validated': 'CUSTOM_VALIDATED',
  'custom-validated-cmd-injection': 'CUSTOM_VALIDATED_CMD_INJECTION',
  'custom-validated-expression-language-injection':
    'CUSTOM_VALIDATED_EXPRESSION_LANGUAGE_INJECTION',
  'custom-validated-header-injection': 'CUSTOM_VALIDATED_HEADER_INJECTION',
  'custom-validated-hql-injection': 'CUSTOM_VALIDATED_HQL_INJECTION',
  'custom-validated-ldap-injection': 'CUSTOM_VALIDATED_LDAP_INJECTION',
  'custom-validated-log-injection': 'CUSTOM_VALIDATED_LOG_INJECTION',
  'custom-validated-nosql-injection': 'CUSTOM_VALIDATED_NOSQL_INJECTIOn',
  'custom-validated-path-traversal': 'CUSTOM_VALIDATED_PATH_TRAVERSAL',
  'custom-validated-redos': 'CUSTOM_VALIDATED_REDOS',
  'custom-validated-reflected-xss': 'CUSTOM_VALIDATED_REFLECTED_XSS',
  'custom-validated-reflection-injection':
    'CUSTOM_VALIDATED_REFLECTION_INJECTION',
  'custom-validated-smtp-injection': 'CUSTOM_VALIDATED_SMTP_INJECTION',
  'custom-validated-sql-injection': 'CUSTOM_VALIDATED_SQL_INJECTION',
  'custom-validated-ssrf': 'CUSTOM_VALIDATED_SSRF',
  'custom-validated-stored-xss': 'CUSTOM_VALIDATED_STORED_XSS',
  'custom-validated-trust-boundary-violation':
    'CUSTOM_VALIDATED_TRUST_BOUNDARY_VIOLATION',
  'custom-validated-unsafe-code-execution':
    'CUSTOM_VALIDATED_UNSAFE_CODE_EXECUTION',
  'custom-validated-unsafe-readline': 'CUSTOM_VALIDATED_UNSAFE_READLINE',
  'custom-validated-unsafe-xml-decode': 'CUSTOM_VALIDATED_UNSAFE_XML_DECODE',
  'custom-validated-untrusted-deserialization':
    'CUSTOM_VALIDATED_UNTRUSTED_DESERIALIZATION',
  'custom-validated-unvalidated-forward':
    'CUSTOM_VALIDATED_UNVALIDATED_FORWARD',
  'custom-validated-unvalidated-redirect':
    'CUSTOM_VALIDATED_UNVALIDATED_REDIRECT',
  'custom-validated-xpath-injection': 'CUSTOM_VALIDATED_XPATH_INJECTION',
  'custom-validated-xxe': 'CUSTOM_VALIDATED_XXE',
  'safe-path': 'SAFE_PATH',

  // tracked-string range tags
  'no-newlines': 'NO_NEWLINES',
  untrusted: 'UNTRUSTED',
  'cross-site': 'CROSS_SITE',
  'limited-chars': 'LIMITED_CHARS',
  'alphanum-space-hyphen': 'ALPHANUM_SPACE_HYPHEN',
  'string-type-checked': 'STRING_TYPE_CHECKED',

  'database-write': 'DATABASE_WRITE'
};

const contrastPkg = require('../package.json');

const AGENT_INFO = {
  VERSION: coerce(contrastPkg.version).version,
  SUPPORTED_VERSIONS: contrastPkg.engines.node,
  SUPPORTED_NPM_VERSIONS: contrastPkg.engines.npm,
  NAME: contrastPkg.name,
  TRACE_VERSION: '4'
};

const CSP_HEADERS = [
  'content-security-policy',
  'x-content-security-policy',
  'x-webkit-csp'
];

const VIRTUAL_PATCH_INPUT_TYPES = {
  UNKNOWN_INPUT: 'UNKNOWN_INPUT',
  USERAGENT: 'USERAGENT',
  REFERER: 'REFERER',
  URL: 'URL',
  PARAMETER: 'PARAMETER',
  HEADER: 'HEADER',
  CODE: 'CODE'
};

const VIRTUAL_PATCH_EVALUATIONS = {
  UNKNOWN_EVALUATION: 'UNKNOWN_EVALUATION',
  MATCHES: 'MATCHES',
  DOESNT_MATCH: 'DOESNT_MATCH',
  CONTAINS: 'CONTAINS',
  DOESNT_CONTAIN: 'DOESNT_CONTAIN',
  EQUALS: 'EQUALS',
  DOESNT_EQUAL: 'DOESNT_EQUAL'
};

const SAFE_HEADER_VALUES = [
  'KEEP-ALIVE',
  'keep-alive',
  '$VERSION=1',
  'gzip,deflate',
  'gzip, deflate',
  'gzip, deflate, sdch',
  'application/x-wwww-form-urlencoded',
  '*/*',
  'max-age=0',
  'https',
  'close',
  '0',
  '443',
  'text/json',
  'text/xml',
  'application/json',
  'application/xml'
];

const TEAMSERVER_API = {
  CHANNEL_DISABLING_STATUS_CODES: [401, 409, 410],
  CHANNEL_PAUSING_STATUS_CODES: [401, 403, 408, 412],
  ERROR_CODE_MESSAGES: {
    400: 'Malformed body content in request',
    401: 'Unknown credentials in API request. Please check configuration for proper credentials.',
    403: 'Unauthorized credentials in API request. Please check configuration for proper credentials.',
    408: 'Agent request timeout.',
    409: 'This application is unwanted by TeamServer and no findings will be reported. Make sure the application is unarchived.',
    410: 'Application not found. Update aborted',
    412: 'API key no longer valid. Please check configuration for proper credentials.',
    500: 'Contrast server error. Please see Contrast server logs for more information.'
  },
  REACTIONS: {
    DISABLE: 'DISABLE',
    NOOP: 'NOOP'
  }
};

const INTERVALS = {
  PREFLIGHT: 5000,
  HEARTBEAT: 30000
};

const RESPONSE_TYPES = {
  NO_ACTION: 'NO_ACTION',
  BLOCKED: 'BLOCKED',
  MONITORED: 'MONITORED',
  PROBED: 'PROBED',
  BLOCKED_AT_PERIMETER: 'BLOCKED_AT_PERIMETER',
  AGGREGATED: 'AGGREGATED'
};

const FRAMEWORKS = ['express', '@hapi/hapi', 'hapi', 'koa', 'fastify'];

const HAPI = {
  FINISHED: 'Hapi.requestFinished',
  ORIG_FUNC: Symbol('originalFunction')
};

// symbol we add to Express layers for storing middleware state
const MW_PATH = Symbol('middlewarePath');
// symbol we add to Express requests storing the layers that have
// been traversed
const LAYER_STACK = Symbol('layerStack');

// symbol for fetching unproxied object from proxy. used with membranes
// to proxy when creating SR messages.
const PROXY_TARGET = Symbol('proxyTarget');

const REQUIRED_SIGNATURE_KEYS = [
  'id',
  'definiteThreshold',
  'watchThreshold',
  'patternSearchers',
  'keywordSearchers',
  'customSearchers'
];

const HTTP_RESPONSE_HOOKED_METHOD_KEYS = {
  WRITE_HEAD: Symbol('writeHead'),
  END: Symbol('end'),
  PUSH: Symbol('push')
};

const PATCH_TYPES = {
  // a patch for a function for emitting architecture component events
  // for flow-map
  ARCH_COMPONENT: 'arch component',
  // a patch related to retaining or applying async context
  ASYNC_CONTEXT: 'async context',
  // patch for a propagator
  ASSESS_PROPAGATOR: 'assess propagator',
  // patch for an assess sink
  ASSESS_SINK: 'assess sink',
  // patch for an assess source
  ASSESS_SOURCE: 'assess source',
  // deadzone - we patch deadzone functions to ensure they
  // are run in no instrumentation scope
  DEADZONE: 'deadzone',
  // generic catch-all for patches we install to instrument
  // HTTP frameworks
  FRAMEWORK: 'framework',
  // used for hooking injected globals that are added
  // during rewrite process
  INJECTION: 'injection',
  // patch for a protect sink (aka sensor)
  PROTECT_SINK: 'protect sink',
  // patch for emitting a protect source event
  PROTECT_SOURCE: 'protect source',
  // patch for tracking route coverage (discovery,observation,et)
  ROUTE_COVERAGE: 'route coverage',
  // like assess and protect sink but a generic patch that
  // provides data to both features
  SINK: 'sink',
  // like assess and protect source but a generic patch that
  // provides data to both features
  SOURCE: 'source',
  // miscellaneous patching - usage is discouraged
  // in most cases better to group with a more specific
  // label (or add one)
  MISC: 'miscellaneous'
};

const SCREENER_HEADER_NAME = 'x-contrast-screener-id';

const EXCLUSION_TAG_NAMESPACE = 'exclusion';

module.exports = {
  ACTIONS,
  AGENT_INFO,
  ASSESS_STACKTRACES,
  ATTACK_STATUS,
  AUTHENTICATION,
  CONNECTION_TYPES,
  CMD_INJECTION_SEMANTIC_TYPES,
  CSP_HEADERS,
  DEBUG_LOG_LEVELS,
  DOCUMENT_TYPES,
  EXCLUSION_MATCH_STRATEGIES,
  EXCLUSION_INPUT_TYPES,
  EXCLUSION_TAG_NAMESPACE,
  EXCLUSION_TYPES,
  EVENT_TYPES,
  FRAMEWORKS,
  LC_HTTP_VERBS,
  HAPI,
  HTTP_VERBS,
  HTTP_EVENTS,
  HTTP_RESPONSE_HOOKED_METHOD_KEYS,
  IMPACTS,
  IMPORTANCE,
  INPUT_TYPES,
  INPUT_TYPES_WITH_PARAMS,
  INSTRUMENTATION_MODE,
  INTERVALS,
  LAYER_STACK,
  PROXY_TARGET,
  MW_PATH,
  PATCH_TYPES,
  PROTECT_RULE_DEFINITION_TYPES,
  PROTECT_RULE_SUPPORTED_MODES,
  PROTECTION_MODES,
  PROTOCOLS,
  REACTION_OPERATION,
  RESPONSE_TYPES,
  REQUIRED_SIGNATURE_KEYS,
  RULES,
  RULE_TYPES,
  SAFE_XSS_CONTENT_TYPES,
  SAFE_HEADER_VALUES,
  SCREENER_HEADER_NAME,
  SCORES,
  SINK_TYPES,
  SYSLOG_SEVERITIES,
  TAGS,
  TEAMSERVER_API,
  THRESHOLDS,
  VIRTUAL_PATCH_EVALUATIONS,
  VIRTUAL_PATCH_INPUT_TYPES,
  WEIGHTS,
  WORD_SHARE
};
