UNPKG

@hclsoftware/secagent

Version:

IAST agent

177 lines (150 loc) 5.67 kB
//IASTIGNORE /* * **************************************************** * Licensed Materials - Property of HCL. * (c) Copyright HCL Technologies Ltd. 2017, 2025. * Note to U.S. Government Users *Restricted Rights. * **************************************************** */ 'use strict' const SessionTracker = require("./SessionTracker"); const Utils = require("./Utils/Utils"); const {ConfigInfo} = require("./ConfigFile/ConfigInfo"); const DastResponseData = require("./IastDast/DastResponseData") const Logger = require('./Logger/IastLogger') const {RequestBody} = require("./Utils/RequestBody") const StackInfo = require("./StackInfo"); function parseQueryString(request, hidePasswords){ return request.query != null ? Object.keys(request.query).map(key => `${key}=${ hidePasswords && SessionTracker.isPasswordName(key) ? Utils.PASSWORD_TEXT : request.query[key]}`).origJoin('&') : request.query } function getFullUrlWithoutQuery(request) { try { const protocol = request.protocol; const host = request.headers.host; const urlWithoutQuery = getUrlWithoutQuery(request.url); return `${protocol}://${host}${urlWithoutQuery}`; } catch (e) { return ''; // Fallback for invalid request object fields or exceptions } } function getUrlWithoutQuery(url) { const queryIndex = url.origIndexOf('?'); if (queryIndex !== -1) { return url.origSubstring(0, queryIndex); } return url; } /** * Safely retrieves a property value or executes a function to get a value from an object. * * @param {Object} obj - The object from which to retrieve the value. * @param {string|string[]|Function} accessor - The property key (string) or a function that takes the object as the first argument. * @param {*} defaultValue - The fallback value to return if retrieval fails. * @param {...any} args - Additional arguments to pass to the accessor function if it's a function. * @returns {*} - The retrieved value or the fallback value. */ function safeGetFrom(obj, accessor, defaultValue, ...args) { try { if (typeof accessor === 'function') { return accessor(obj, ...args); } // accessor is an array if (Array.isArray(accessor)) { for (const key of accessor) { if (key in obj) { obj = obj[key]; } } return obj } // if accessor is a string return obj[accessor]; } catch (error) { //Logger.eventLog.info(`Error accessing '${typeof accessor === 'function' ? accessor.name : accessor}': ${error.message}`); return defaultValue; } } class RequestInfo { /* use Object.Assign method for each source container because the original containers are replaced by proxies * and we dont want to apply their hooks when we access them in our code. */ constructor (request, dastRequestData, serverFlowTags) { this.uri = safeGetFrom(request, '_parsedUrl', 'null') != null ? safeGetFrom(request, ['_parsedUrl', 'pathname'], '') : safeGetFrom(request, 'url', '') this.url = safeGetFrom(request, 'url', '') this.fullUrlWithoutQuery = safeGetFrom(request, getFullUrlWithoutQuery, ''); this.queryString = safeGetFrom(request, parseQueryString, '', ConfigInfo.ConfigInfo.hidePasswords) this.method = safeGetFrom(request, 'method', '') this.queryParameters = Object.assign({}, safeGetFrom(request, 'query', {})) this.routeParameters = Object.assign({}, safeGetFrom(request, 'params', {})) this.allParameters = Object.assign({}, this.queryParameters, this.routeParameters) this.headers = Object.assign({}, safeGetFrom(request, 'headers', {})) this.body = new RequestBody(this.headers["content-type"]) this.isSecure = safeGetFrom(request, 'secure', undefined) this.usedParameters = new Set() this.usedheaders = new Set() this.usedCookies = new Set() this.dastRequestData = dastRequestData if (this.dastRequestData != null) { // create empty response data this.dastResponseData = new DastResponseData(); } this.serverFlowTags = serverFlowTags } clone() { return Object.assign(Object.create(Object.getPrototypeOf(this)), this) } updateBodyParameters(body) { this.body.data = body Object.assign(this.allParameters, body) } getInfoForReporting() { const reportObject = { uri: this.uri, queryString: this.queryString, method: this.method, } try { const reportingBody = this.body.getReportingJson() if (reportingBody != null) { reportObject.body = reportingBody } } catch (error) { Logger.eventLog.error(error) } return this.trimReportingValuesIfNeeded(reportObject) } trimReportingValuesIfNeeded(reportObject) { reportObject.uri = StackInfo.asString(reportObject.uri) reportObject.queryString = StackInfo.asString(reportObject.queryString) return reportObject } addUsedParameter(name) { this.usedParameters.add(name) } addUsedHeader(name) { this.usedheaders.add(name) } addUsedCookie(name) { this.usedCookies.add(name) } isUsedParameter(name) { return this.usedParameters.has(name) } isUsedHeader(name) { return this.usedheaders.has(name) } clearUsedCookies() { this.usedCookies.clear() } hasDastRequestData() { return this.dastRequestData != null; } addSinkReportToDastResponse(url, entity, stack, vulnerability, isExtra) { this.dastResponseData.addSinkReport(url, entity, stack, vulnerability, isExtra); } setRouteTemplateInDastResponse(routeTemplate) { this.dastResponseData.setRouteTemplate(routeTemplate); } } module.exports = RequestInfo