UNPKG

dd-trace

Version:

Datadog APM tracing client for JavaScript

183 lines (149 loc) 5.04 kB
'use strict' const { storage } = require('../../../../../datadog-core') const { getNonDDCallSiteFrames } = require('../path-line') const { getIastContext, getIastStackTraceId } = require('../iast-context') const overheadController = require('../overhead-controller') const { SinkIastPlugin } = require('../iast-plugin') const { addVulnerability, getVulnerabilityCallSiteFrames, replaceCallSiteFromSourceMap } = require('../vulnerability-reporter') const { getMarkFromVulnerabilityType } = require('../taint-tracking/secure-marks') const { SUPPRESSED_VULNERABILITIES } = require('../telemetry/iast-metric') class Analyzer extends SinkIastPlugin { constructor (type) { super() this._type = type this._secureMark = getMarkFromVulnerabilityType(type) } _isVulnerable (value, context) { return false } _isExcluded (location) { return false } _report (value, context, meta) { const evidence = this._getEvidence(value, context, meta) this._reportEvidence(value, context, evidence) } _reportEvidence (value, context, evidence) { const callSiteFrames = getVulnerabilityCallSiteFrames() const nonDDCallSiteFrames = getNonDDCallSiteFrames(callSiteFrames, this._getExcludedPaths()) const location = this._getLocation(value, nonDDCallSiteFrames) if (!this._isExcluded(location)) { const originalLocation = this._getOriginalLocation(location) const spanId = context?.rootSpan?.context().toSpanId() const stackId = getIastStackTraceId(context) const vulnerability = this._createVulnerability( this._type, evidence, spanId, originalLocation, stackId ) addVulnerability(context, vulnerability, nonDDCallSiteFrames) } } _reportIfVulnerable (value, context, meta) { if (this._isVulnerable(value, context) && this._checkOCE(context, value)) { this._report(value, context, meta) return true } return false } _getEvidence (value) { return { value } } _getLocation (value, callSiteFrames) { return callSiteFrames[0] } _getOriginalLocation (location) { const locationFromSourceMap = replaceCallSiteFromSourceMap(location) const originalLocation = {} if (locationFromSourceMap?.path) { originalLocation.path = locationFromSourceMap.path } if (locationFromSourceMap?.line) { originalLocation.line = locationFromSourceMap.line } if (location?.class_name) { originalLocation.class = location.class_name } if (location?.function) { originalLocation.method = location.function } return originalLocation } _getExcludedPaths () {} _isInvalidContext (store, iastContext) { return store && !iastContext } analyze (value, store = storage('legacy').getStore(), meta) { const iastContext = getIastContext(store) if (this._isInvalidContext(store, iastContext)) return this._reportIfVulnerable(value, iastContext, meta) } analyzeAll (...values) { const store = storage('legacy').getStore() const iastContext = getIastContext(store) if (this._isInvalidContext(store, iastContext)) return for (const value of values) { if (this._isVulnerable(value, iastContext)) { // TODO(BridgeAR): Here are multiple cases that receive a different // number of arguments than passed through. Fix those cases. if (this._checkOCE(iastContext, value)) { this._report(value, iastContext) } break } } } _checkOCE (context) { return overheadController.hasQuota(overheadController.OPERATIONS.REPORT_VULNERABILITY, context, this._type) } _createVulnerability (type, evidence, spanId, location, stackId) { if (type && evidence) { const _spanId = spanId || 0 return { type, evidence, location: { spanId: _spanId, stackId, ...location }, hash: this._createHash(this._createHashSource(type, evidence, location)) } } return null } _createHashSource (type, evidence, location) { return location ? `${type}:${location.path}:${location.line}` : type } _createHash (hashSource) { let hash = 0 let offset = 0 const size = hashSource.length for (let i = 0; i < size; i++) { hash = ((hash << 5) - hash) + hashSource.charCodeAt(offset++) } return hash } _getSuppressedMetricTag () { if (!this._suppressedMetricTag) { this._suppressedMetricTag = SUPPRESSED_VULNERABILITIES.formatTags(this._type)[0] } return this._suppressedMetricTag } _incrementSuppressedMetric (iastContext) { SUPPRESSED_VULNERABILITIES.inc(iastContext, this._getSuppressedMetricTag()) } addSub (iastSubOrChannelName, handler) { const iastSub = typeof iastSubOrChannelName === 'string' ? { channelName: iastSubOrChannelName } : iastSubOrChannelName super.addSub({ tag: this._type, ...iastSub }, handler) } } module.exports = Analyzer