@contrast/assess 1.53.0 → 1.54.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/crypto-analysis/install/math.js +0 -1
- package/lib/dataflow/propagation/common.js +6 -6
- package/lib/dataflow/propagation/install/JSON/parse.js +7 -3
- package/lib/dataflow/propagation/install/JSON/stringify.js +7 -6
- package/lib/dataflow/propagation/install/array-prototype-join.js +5 -8
- package/lib/dataflow/propagation/install/buffer.js +4 -4
- package/lib/dataflow/propagation/install/contrast-methods/add.js +42 -38
- package/lib/dataflow/propagation/install/contrast-methods/string.js +4 -2
- package/lib/dataflow/propagation/install/contrast-methods/tag.js +3 -1
- package/lib/dataflow/propagation/install/decode-uri-component.js +5 -7
- package/lib/dataflow/propagation/install/ejs/escape-xml.js +4 -3
- package/lib/dataflow/propagation/install/ejs/template.js +1 -1
- package/lib/dataflow/propagation/install/encode-uri.js +5 -7
- package/lib/dataflow/propagation/install/escape-html.js +4 -3
- package/lib/dataflow/propagation/install/escape.js +5 -7
- package/lib/dataflow/propagation/install/handlebars-utils-escape-expression.js +4 -3
- package/lib/dataflow/propagation/install/joi/boolean.js +1 -3
- package/lib/dataflow/propagation/install/joi/expression.js +1 -3
- package/lib/dataflow/propagation/install/joi/number.js +1 -3
- package/lib/dataflow/propagation/install/joi/string-schema.js +2 -6
- package/lib/dataflow/propagation/install/joi/utils.js +2 -4
- package/lib/dataflow/propagation/install/joi/values.js +1 -3
- package/lib/dataflow/propagation/install/mongoose/schema-map.js +1 -3
- package/lib/dataflow/propagation/install/mongoose/schema-mixed.js +1 -3
- package/lib/dataflow/propagation/install/mongoose/schema-string.js +4 -5
- package/lib/dataflow/propagation/install/mustache-escape.js +4 -3
- package/lib/dataflow/propagation/install/mysql-connection-escape.js +9 -8
- package/lib/dataflow/propagation/install/path/basename.js +6 -7
- package/lib/dataflow/propagation/install/path/common.js +1 -0
- package/lib/dataflow/propagation/install/path/dirname.js +6 -8
- package/lib/dataflow/propagation/install/path/extname.js +8 -22
- package/lib/dataflow/propagation/install/path/format.js +6 -10
- package/lib/dataflow/propagation/install/path/join-and-resolve.js +7 -13
- package/lib/dataflow/propagation/install/path/normalize.js +8 -18
- package/lib/dataflow/propagation/install/path/parse.js +8 -18
- package/lib/dataflow/propagation/install/path/relative.js +8 -15
- package/lib/dataflow/propagation/install/path/toNamespacedPath.js +7 -18
- package/lib/dataflow/propagation/install/pug/index.js +1 -1
- package/lib/dataflow/propagation/install/pug-runtime-escape.js +6 -5
- package/lib/dataflow/propagation/install/querystring/escape.js +3 -1
- package/lib/dataflow/propagation/install/querystring/parse.js +3 -2
- package/lib/dataflow/propagation/install/querystring/stringify.js +4 -4
- package/lib/dataflow/propagation/install/reg-exp-prototype-exec.js +4 -3
- package/lib/dataflow/propagation/install/sequelize/query-generator.js +0 -1
- package/lib/dataflow/propagation/install/sequelize/sql-string.js +16 -17
- package/lib/dataflow/propagation/install/sql-template-strings.js +6 -10
- package/lib/dataflow/propagation/install/string/concat.js +4 -4
- package/lib/dataflow/propagation/install/string/format-methods.js +4 -4
- package/lib/dataflow/propagation/install/string/html-methods.js +5 -6
- package/lib/dataflow/propagation/install/string/index.js +4 -3
- package/lib/dataflow/propagation/install/string/match-all.js +7 -6
- package/lib/dataflow/propagation/install/string/match.js +10 -9
- package/lib/dataflow/propagation/install/string/replace.js +173 -158
- package/lib/dataflow/propagation/install/string/slice.js +4 -3
- package/lib/dataflow/propagation/install/string/split.js +11 -11
- package/lib/dataflow/propagation/install/string/substring.js +4 -3
- package/lib/dataflow/propagation/install/string/trim.js +4 -3
- package/lib/dataflow/propagation/install/unescape.js +6 -14
- package/lib/dataflow/propagation/install/url/domain-parsers.js +6 -5
- package/lib/dataflow/propagation/install/url/parse.js +17 -17
- package/lib/dataflow/propagation/install/url/searchParams.js +36 -25
- package/lib/dataflow/propagation/install/url/url.js +3 -2
- package/lib/dataflow/propagation/install/util-format.js +4 -3
- package/lib/dataflow/propagation/install/validator/hooks.js +0 -1
- package/lib/dataflow/sinks/install/eval.js +3 -1
- package/lib/dataflow/sinks/install/function.js +3 -4
- package/lib/dataflow/sinks/install/marsdb.js +3 -1
- package/lib/dataflow/sinks/install/mongodb.js +3 -1
- package/lib/dataflow/sinks/install/mssql.js +4 -3
- package/lib/dataflow/sinks/install/mysql.js +3 -1
- package/lib/dataflow/sinks/install/restify.js +3 -1
- package/lib/dataflow/sinks/install/sqlite3.js +4 -2
- package/lib/dataflow/sinks/install/vm.js +6 -4
- package/lib/dataflow/sources/handler.js +2 -3
- package/lib/dataflow/sources/install/fastify/fastify.js +4 -4
- package/lib/dataflow/tag-utils.js +15 -1
- package/lib/dataflow/tracker.js +0 -5
- package/lib/event-factory.js +1 -1
- package/lib/session-configuration/install/express-session.js +0 -1
- package/lib/session-configuration/install/fastify-cookie.js +0 -3
- package/lib/session-configuration/install/hapi.js +0 -1
- package/lib/session-configuration/install/koa.js +0 -3
- package/package.json +10 -10
|
@@ -23,7 +23,8 @@ const {
|
|
|
23
23
|
StringPrototypeReplace,
|
|
24
24
|
StringPrototypeReplaceAll,
|
|
25
25
|
StringPrototypeSubstring
|
|
26
|
-
}
|
|
26
|
+
},
|
|
27
|
+
isString,
|
|
27
28
|
} = require('@contrast/common');
|
|
28
29
|
const {
|
|
29
30
|
createSubsetTags,
|
|
@@ -43,170 +44,176 @@ module.exports = function(core) {
|
|
|
43
44
|
},
|
|
44
45
|
} = core;
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// convert replace args (match, p1, p2, ..., matchIdx, str, ?groups) to
|
|
49
|
-
// re.exec(string) format [match, g1, g2, ..., index: N, input: '', groups?]
|
|
50
|
-
//
|
|
51
|
-
const r = [];
|
|
52
|
-
let ix = -1;
|
|
53
|
-
if (typeof args.at(-1) === 'object') {
|
|
54
|
-
r.groups = args.at(-1);
|
|
55
|
-
ix = -2;
|
|
56
|
-
}
|
|
57
|
-
r.input = args.at(ix);
|
|
58
|
-
ix -= 1;
|
|
59
|
-
r.index = args.at(ix);
|
|
47
|
+
const RE_REPS = /\$(\$|&|`|'|[1-9][0-9]?|<[a-zA-Z0-9_]+>)/g;
|
|
48
|
+
const STR_REPS = /\$(\$|&|`|')/g;
|
|
60
49
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
const propagator = core.assess.dataflow.propagation.stringInstrumentation.replace = {
|
|
51
|
+
//
|
|
52
|
+
parseArgs(args) {
|
|
53
|
+
//
|
|
54
|
+
// convert replace args (match, p1, p2, ..., matchIdx, str, ?groups) to
|
|
55
|
+
// re.exec(string) format [match, g1, g2, ..., index: N, input: '', groups?]
|
|
56
|
+
//
|
|
57
|
+
const r = [];
|
|
58
|
+
let ix = -1;
|
|
59
|
+
if (typeof args.at(-1) === 'object') {
|
|
60
|
+
r.groups = args.at(-1);
|
|
61
|
+
ix = -2;
|
|
62
|
+
}
|
|
63
|
+
r.input = args.at(ix);
|
|
64
|
+
ix -= 1;
|
|
65
|
+
r.index = args.at(ix);
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
// ix is negative from the end, so add it
|
|
68
|
+
ix = args.length + ix;
|
|
69
|
+
for (let i = 0; i < ix; i++) {
|
|
70
|
+
r.push(args[i]);
|
|
71
|
+
}
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
return r;
|
|
74
|
+
},
|
|
75
|
+
//
|
|
76
|
+
getReplacementInfo(data, replacerArgs, parsedArgs) {
|
|
77
|
+
// patternIsRE is two different flags, both booleans.
|
|
78
|
+
// - set true if the first argument to String.prototype.replace is an RE.
|
|
79
|
+
// - after the $N, $<name> checks, it flags that a substitution was made.
|
|
80
|
+
const patternIsRE = data.args[0] instanceof RegExp;
|
|
81
|
+
let replacement;
|
|
82
|
+
if (typeof data._replacement === 'function') {
|
|
83
|
+
// no special replacements apply to the string returned by a replacement
|
|
84
|
+
// function.
|
|
85
|
+
replacement = data._replacement.call(global, ...replacerArgs);
|
|
86
|
+
} else {
|
|
87
|
+
// if it's not a function then the valid special replacements depend on
|
|
88
|
+
// whether the pattern is a regex or a string. first find substitution
|
|
89
|
+
// patterns present in the replacement string. Don't find patterns that
|
|
90
|
+
// aren't valid, e.g., $0, $<name> when the pattern is a string.
|
|
91
|
+
replacement = String(data._replacement);
|
|
72
92
|
|
|
73
|
-
|
|
74
|
-
// patternIsRE is two different flags, both booleans.
|
|
75
|
-
// - set true if the first argument to String.prototype.replace is an RE.
|
|
76
|
-
// - after the $N, $<name> checks, it flags that a substitution was made.
|
|
77
|
-
const patternIsRE = data.args[0] instanceof RegExp;
|
|
78
|
-
let replacement;
|
|
79
|
-
if (typeof data._replacement === 'function') {
|
|
80
|
-
// no special replacements apply to the string returned by a replacement
|
|
81
|
-
// function.
|
|
82
|
-
replacement = data._replacement.call(global, ...replacerArgs);
|
|
83
|
-
} else {
|
|
84
|
-
// if it's not a function then the valid special replacements depend on
|
|
85
|
-
// whether the pattern is a regex or a string. first find substitution
|
|
86
|
-
// patterns present in the replacement string. Don't find patterns that
|
|
87
|
-
// aren't valid, e.g., $0, $<name> when the pattern is a string.
|
|
88
|
-
replacement = String(data._replacement);
|
|
93
|
+
const matches = StringPrototypeMatchAll.call(replacement, patternIsRE ? RE_REPS : STR_REPS);
|
|
89
94
|
|
|
90
|
-
|
|
95
|
+
for (const m of matches) {
|
|
96
|
+
let substitution;
|
|
97
|
+
let substitutionDone = false;
|
|
98
|
+
// format of m: ['$`', '`', index: 0, input: string, groups: undefined|{}]
|
|
99
|
+
// if the pattern is a regex, then $1 to $99 and $<name> are valid
|
|
100
|
+
if (patternIsRE) {
|
|
101
|
+
// my guess is $1 to $99 are most likely, after that, who knows? so
|
|
102
|
+
// we check named groups next, because 1) they seem more useful than
|
|
103
|
+
// the other $ patterns and 2) they are in the same patternIsRE test.
|
|
104
|
+
//
|
|
105
|
+
// in any case, the following will be false if m[1][0] is not a number.
|
|
106
|
+
if (m[1][0] >= 1 && m[1][0] <= 9) {
|
|
107
|
+
// a group might not be present, e.g., (pattern)?(a) or (a)|(b).
|
|
108
|
+
if (parsedArgs[m[1]] === undefined) {
|
|
109
|
+
if (m[1] in parsedArgs) {
|
|
110
|
+
// need to remove $m[1] from replacement pattern. N.B. this could
|
|
111
|
+
// mess up if the replacement text contains text that matches a
|
|
112
|
+
// subsequent replacement (either RE or string).
|
|
113
|
+
replacement = StringPrototypeReplaceAll.call(replacement, m[0], '');
|
|
114
|
+
} else {
|
|
115
|
+
// no capture groups in RegExp
|
|
116
|
+
substitution = replacement;
|
|
117
|
+
}
|
|
91
118
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// mess up if the replacement text contains text that matches a
|
|
109
|
-
// subsequent replacement (either RE or string).
|
|
110
|
-
replacement = StringPrototypeReplaceAll.call(replacement, m[0], '');
|
|
111
|
-
continue;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
substitution = parsedArgs[m[1]];
|
|
122
|
+
substitutionDone = true;
|
|
123
|
+
} else if (m[1][0] === '<') {
|
|
124
|
+
// named group
|
|
125
|
+
const groupName = StringPrototypeSubstring.call(m[1], 1, m[1].length - 1);
|
|
126
|
+
if (parsedArgs.groups[groupName] === undefined && groupName in parsedArgs.groups) {
|
|
127
|
+
// remove $<groupName> from the replacement pattern. N.B. this
|
|
128
|
+
// also could mess up if the replacement text containts text that
|
|
129
|
+
// matches a subsequent replacement.
|
|
130
|
+
replacement = StringPrototypeReplaceAll.call(replacement, m[0], '');
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
substitution = parsedArgs.groups[groupName];
|
|
134
|
+
substitutionDone = true;
|
|
112
135
|
}
|
|
113
|
-
substitution = parsedArgs[m[1]];
|
|
114
|
-
substitutionDone = true;
|
|
115
|
-
} else if (m[1][0] === '<') {
|
|
116
|
-
// named group
|
|
117
|
-
const groupName = StringPrototypeSubstring.call(m[1], 1, m[1].length - 1);
|
|
118
|
-
if (parsedArgs.groups[groupName] === undefined && groupName in parsedArgs.groups) {
|
|
119
|
-
// remove $<groupName> from the replacement pattern. N.B. this
|
|
120
|
-
// also could mess up if the replacement text containts text that
|
|
121
|
-
// matches a subsequent replacement.
|
|
122
|
-
replacement = StringPrototypeReplaceAll.call(replacement, m[0], '');
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
substitution = parsedArgs.groups[groupName];
|
|
126
|
-
substitutionDone = true;
|
|
127
136
|
}
|
|
128
|
-
}
|
|
129
137
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
138
|
+
// the following are valid whether the pattern is a regex or a string.
|
|
139
|
+
//
|
|
140
|
+
// any idea what order $&'` should be in from a most-common to least-
|
|
141
|
+
// common perspective? nfi.
|
|
142
|
+
let substitutionTags;
|
|
143
|
+
if (!substitutionDone) {
|
|
144
|
+
if (m[1] === '$') {
|
|
145
|
+
// this could actually be tracked but in order to do this "right"
|
|
146
|
+
// we have to be able to distinguish whether it is the first or
|
|
147
|
+
// the second $ that is tracked. so punt, and just ignore it, as
|
|
148
|
+
// originally implemented.
|
|
149
|
+
substitution = '$';
|
|
150
|
+
data._replacementOffset -= 1;
|
|
151
|
+
} else if (m[1] === '&') {
|
|
152
|
+
// replace these '$&' in parsedArgs[0] (replacerArgs[0], i.e., the
|
|
153
|
+
// match). if tracked, handle it. do so by index, so we don't have to
|
|
154
|
+
// call replace again? e.g., string[m.index..m.index+2]
|
|
155
|
+
substitution = parsedArgs[0];
|
|
156
|
+
} else if (m[1] === '`') {
|
|
157
|
+
const info = tracker.getData(parsedArgs.input);
|
|
158
|
+
substitution = StringPrototypeSubstring.call(parsedArgs.input, 0, parsedArgs.index);
|
|
159
|
+
substitutionTags = createSubsetTags(info.tags, parsedArgs.index, substitution.length);
|
|
160
|
+
} else if (m[1] === "'") {
|
|
161
|
+
const info = tracker.getData(parsedArgs.input);
|
|
162
|
+
substitution = StringPrototypeSubstring.call(parsedArgs.input, parsedArgs.index + parsedArgs[0].length);
|
|
163
|
+
substitutionTags = createSubsetTags(info.tags, parsedArgs.index, substitution.length);
|
|
164
|
+
} // else {
|
|
165
|
+
// throw new Error('how can it have matched RE and gotten here?');
|
|
166
|
+
// }
|
|
167
|
+
// i'm not sure what the proper handling of this is. if either char
|
|
168
|
+
// of the $$&`' sequence is tracked, then something the user input
|
|
169
|
+
// is manipulating the output, even if it is just duplicating what
|
|
170
|
+
// might be tracked or untracked input. does that count?
|
|
171
|
+
}
|
|
172
|
+
replacement = StringPrototypeReplace.call(replacement, m[0], substitution);
|
|
173
|
+
if (!substitutionTags && tracker.getData(substitution)) substitutionTags = tracker.getData(substitution)?.tags;
|
|
174
|
+
if (substitutionTags) {
|
|
175
|
+
data._replacementTags = createAppendTags(data._replacementTags || {}, substitutionTags, m.index + data._replacementOffset);
|
|
176
|
+
data._replacementOffset += (substitution.length - m[0].length);
|
|
177
|
+
}
|
|
169
178
|
}
|
|
170
179
|
}
|
|
171
|
-
}
|
|
172
180
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
data._replacementInfo = tracker.getData(replacement);
|
|
177
|
-
if (data._replacementInfo) {
|
|
178
|
-
data._history.add(data._replacementInfo);
|
|
179
|
-
}
|
|
181
|
+
// coerce the replacement to a string, e.g., null => 'null'
|
|
182
|
+
replacement = String(replacement);
|
|
180
183
|
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
data._replacementInfo = tracker.getData(replacement);
|
|
185
|
+
if (data._replacementInfo) {
|
|
186
|
+
data._history.add(data._replacementInfo);
|
|
187
|
+
}
|
|
183
188
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
+
return { replacement, replacementTags: data._replacementTags || data._replacementInfo?.tags };
|
|
190
|
+
},
|
|
191
|
+
//
|
|
192
|
+
getReplacer(data) {
|
|
193
|
+
return function replacer(...args) {
|
|
194
|
+
const parsedArgs = propagator.parseArgs(args);
|
|
195
|
+
const match = parsedArgs[0];
|
|
196
|
+
const { index, input } = parsedArgs;
|
|
189
197
|
|
|
190
|
-
|
|
191
|
-
|
|
198
|
+
const { _accumOffset, _accumTags } = data;
|
|
199
|
+
const { replacement, replacementTags } = propagator.getReplacementInfo(data, args, parsedArgs);
|
|
192
200
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
201
|
+
const preTags = createSubsetTags(_accumTags, 0, _accumOffset + index);
|
|
202
|
+
const postTags = createSubsetTags(_accumTags, _accumOffset + index + match.length, input.length - index - match.length);
|
|
203
|
+
data._accumOffset += (replacement.length - match.length);
|
|
204
|
+
if (preTags || postTags || replacementTags) {
|
|
205
|
+
data._accumTags = createAppendTags(
|
|
206
|
+
createAppendTags(preTags, replacementTags, _accumOffset + index),
|
|
207
|
+
postTags,
|
|
208
|
+
data._accumOffset + index + match.length
|
|
209
|
+
);
|
|
210
|
+
} else {
|
|
211
|
+
data._accumTags = {};
|
|
212
|
+
}
|
|
213
|
+
return replacement;
|
|
214
|
+
};
|
|
215
|
+
},
|
|
208
216
|
|
|
209
|
-
return core.assess.dataflow.propagation.stringInstrumentation.replace = {
|
|
210
217
|
install() {
|
|
211
218
|
const name = 'String.prototype.replace';
|
|
212
219
|
const store = { name, lock: true };
|
|
@@ -215,20 +222,27 @@ module.exports = function(core) {
|
|
|
215
222
|
patchType,
|
|
216
223
|
usePerf: 'sync',
|
|
217
224
|
around(next, data) {
|
|
218
|
-
|
|
225
|
+
const _next = !scopes.instrumentation.isLocked() ? () => scopes.instrumentation.run(store, next) : next;
|
|
226
|
+
|
|
227
|
+
if (!getPropagatorContext()) return _next();
|
|
219
228
|
|
|
220
229
|
// setup state
|
|
221
230
|
data._objInfo = tracker.getData(data.obj);
|
|
222
231
|
data._replacement = data.args[1];
|
|
223
|
-
data._replacementType = typeof data._replacement;
|
|
224
232
|
data._history = data._objInfo ? new Set([data._objInfo]) : new Set();
|
|
225
233
|
data._accumTags = data._objInfo?.tags || {};
|
|
226
234
|
data._accumOffset = 0;
|
|
227
235
|
data._replacementOffset = 0;
|
|
228
236
|
|
|
229
|
-
|
|
237
|
+
// bail early if no constituents are tracked
|
|
238
|
+
if (
|
|
239
|
+
!data._objInfo &&
|
|
240
|
+
isString(data.args[1]) &&
|
|
241
|
+
!tracker.getData(data.args[1])
|
|
242
|
+
) return _next();
|
|
230
243
|
|
|
231
|
-
|
|
244
|
+
data.args[1] = propagator.getReplacer(data);
|
|
245
|
+
const result = _next();
|
|
232
246
|
|
|
233
247
|
if (
|
|
234
248
|
!result ||
|
|
@@ -237,7 +251,7 @@ module.exports = function(core) {
|
|
|
237
251
|
data.obj === result
|
|
238
252
|
) return result;
|
|
239
253
|
|
|
240
|
-
const { obj, args: origArgs, hooked
|
|
254
|
+
const { obj, args: origArgs, hooked } = data;
|
|
241
255
|
const args = [];
|
|
242
256
|
if (tracker.getData(origArgs[0])) {
|
|
243
257
|
args.push({ tracked: true, value: origArgs[0] });
|
|
@@ -254,7 +268,9 @@ module.exports = function(core) {
|
|
|
254
268
|
name,
|
|
255
269
|
moduleName: 'String',
|
|
256
270
|
methodName: 'prototype.replace',
|
|
257
|
-
context
|
|
271
|
+
get context() {
|
|
272
|
+
return `'${obj}'.replace(${ArrayPrototypeJoin.call(args.map(a => a.value))})`;
|
|
273
|
+
},
|
|
258
274
|
history: Array.from(data._history),
|
|
259
275
|
object: {
|
|
260
276
|
value: obj,
|
|
@@ -268,16 +284,13 @@ module.exports = function(core) {
|
|
|
268
284
|
tags: data._accumTags,
|
|
269
285
|
stacktraceOpts: {
|
|
270
286
|
constructorOpt: hooked,
|
|
271
|
-
prependFrames: [orig]
|
|
272
287
|
},
|
|
273
288
|
source: data._objInfo ? (data._history.size > 1 ? 'A' : 'O') : 'P',
|
|
274
289
|
target: 'R',
|
|
275
290
|
});
|
|
276
|
-
|
|
277
|
-
if (!event) return;
|
|
291
|
+
if (!event) return null;
|
|
278
292
|
|
|
279
293
|
const { extern } = tracker.track(result, event);
|
|
280
|
-
|
|
281
294
|
return extern;
|
|
282
295
|
}
|
|
283
296
|
});
|
|
@@ -286,4 +299,6 @@ module.exports = function(core) {
|
|
|
286
299
|
String.prototype.replace = patcher.unwrap(String.prototype.replace);
|
|
287
300
|
}
|
|
288
301
|
};
|
|
302
|
+
|
|
303
|
+
return propagator;
|
|
289
304
|
};
|
|
@@ -55,7 +55,7 @@ module.exports = function(core) {
|
|
|
55
55
|
patchType,
|
|
56
56
|
usePerf: 'sync',
|
|
57
57
|
post(data) {
|
|
58
|
-
const { name, args: origArgs, obj, result, hooked
|
|
58
|
+
const { name, args: origArgs, obj, result, hooked } = data;
|
|
59
59
|
if (!result || !getPropagatorContext()) return;
|
|
60
60
|
|
|
61
61
|
const objInfo = tracker.getData(obj);
|
|
@@ -80,7 +80,9 @@ module.exports = function(core) {
|
|
|
80
80
|
name,
|
|
81
81
|
moduleName: 'String',
|
|
82
82
|
methodName: 'prototype.slice',
|
|
83
|
-
context
|
|
83
|
+
get context() {
|
|
84
|
+
return `'${objInfo.value}'.slice(${ArrayPrototypeJoin.call(args.map(a => a.value), ', ')})`;
|
|
85
|
+
},
|
|
84
86
|
history: [objInfo],
|
|
85
87
|
object: {
|
|
86
88
|
value: obj,
|
|
@@ -96,7 +98,6 @@ module.exports = function(core) {
|
|
|
96
98
|
target: 'R',
|
|
97
99
|
stacktraceOpts: {
|
|
98
100
|
constructorOpt: hooked,
|
|
99
|
-
prependFrames: [orig]
|
|
100
101
|
}
|
|
101
102
|
});
|
|
102
103
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const { primordials: { ArrayPrototypeJoin, RegExpPrototypeExec } } = require('@contrast/common');
|
|
19
|
-
const { createSubsetTags
|
|
19
|
+
const { createSubsetTags } = require('../../../tag-utils');
|
|
20
20
|
const { patchType } = require('../../common');
|
|
21
21
|
|
|
22
22
|
module.exports = function(core) {
|
|
@@ -46,7 +46,7 @@ module.exports = function(core) {
|
|
|
46
46
|
next();
|
|
47
47
|
},
|
|
48
48
|
post(data) {
|
|
49
|
-
const { name, args: origArgs, obj, result, hooked
|
|
49
|
+
const { name, args: origArgs, obj, result, hooked } = data;
|
|
50
50
|
const splitterIsRx = origArgs[0] instanceof RegExp;
|
|
51
51
|
|
|
52
52
|
if (
|
|
@@ -81,7 +81,7 @@ module.exports = function(core) {
|
|
|
81
81
|
if (tags) {
|
|
82
82
|
const metadata = makeEvent({
|
|
83
83
|
result: { tracked: true, value: result[i] },
|
|
84
|
-
tags
|
|
84
|
+
tags,
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
if (metadata) {
|
|
@@ -115,7 +115,7 @@ module.exports = function(core) {
|
|
|
115
115
|
if (tags) {
|
|
116
116
|
const metadata = makeEvent({
|
|
117
117
|
result: { tracked: true, value: result[i] },
|
|
118
|
-
tags
|
|
118
|
+
tags,
|
|
119
119
|
});
|
|
120
120
|
eventFactory.createdEvents.add(metadata);
|
|
121
121
|
const { extern } = tracker.track(result[i], metadata);
|
|
@@ -137,28 +137,28 @@ module.exports = function(core) {
|
|
|
137
137
|
const args = origArgs.map((arg) => {
|
|
138
138
|
const argInfo = tracker.getData(arg);
|
|
139
139
|
return argInfo ?
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
{ tracked: true, value: argInfo.value } :
|
|
141
|
+
{ tracked: false, value: splitterIsRx ? arg.toString() : `'${arg}'` };
|
|
142
142
|
});
|
|
143
143
|
_event = eventFactory.createPropagationEvent({
|
|
144
144
|
name,
|
|
145
145
|
moduleName: 'String',
|
|
146
146
|
methodName: 'prototype.split',
|
|
147
|
-
context
|
|
147
|
+
get context() {
|
|
148
|
+
return `'${objInfo.value}'.split(${ArrayPrototypeJoin.call(args.map(a => a.value))})`;
|
|
149
|
+
},
|
|
148
150
|
history: [objInfo],
|
|
149
151
|
object: {
|
|
150
152
|
value: obj,
|
|
151
153
|
tracked: true,
|
|
152
154
|
},
|
|
153
155
|
args,
|
|
154
|
-
tags: {},
|
|
155
156
|
result: {
|
|
156
|
-
value:
|
|
157
|
-
tracked:
|
|
157
|
+
value: `${result}`,
|
|
158
|
+
tracked: true
|
|
158
159
|
},
|
|
159
160
|
stacktraceOpts: {
|
|
160
161
|
constructorOpt: hooked,
|
|
161
|
-
prependFrames: [orig]
|
|
162
162
|
},
|
|
163
163
|
source: 'O',
|
|
164
164
|
target: 'R'
|
|
@@ -63,7 +63,7 @@ module.exports = function(core) {
|
|
|
63
63
|
patchType,
|
|
64
64
|
usePerf: 'sync',
|
|
65
65
|
post(data) {
|
|
66
|
-
const { obj, args: origArgs, result, name, hooked
|
|
66
|
+
const { obj, args: origArgs, result, name, hooked } = data;
|
|
67
67
|
if (!result || !getPropagatorContext()) return;
|
|
68
68
|
|
|
69
69
|
const objInfo = tracker.getData(obj);
|
|
@@ -90,7 +90,9 @@ module.exports = function(core) {
|
|
|
90
90
|
name,
|
|
91
91
|
moduleName: 'String',
|
|
92
92
|
methodName: 'prototype.substring',
|
|
93
|
-
context
|
|
93
|
+
get context() {
|
|
94
|
+
return `'${objInfo.value}'.substring(${ArrayPrototypeJoin.call(args.map(a => a.value))})`;
|
|
95
|
+
},
|
|
94
96
|
history: [objInfo],
|
|
95
97
|
object: {
|
|
96
98
|
value: obj,
|
|
@@ -105,7 +107,6 @@ module.exports = function(core) {
|
|
|
105
107
|
source: 'O',
|
|
106
108
|
stacktraceOpts: {
|
|
107
109
|
constructorOpt: hooked,
|
|
108
|
-
prependFrames: [orig]
|
|
109
110
|
},
|
|
110
111
|
target: 'R',
|
|
111
112
|
});
|
|
@@ -30,7 +30,7 @@ module.exports = function(core) {
|
|
|
30
30
|
|
|
31
31
|
function createPostHook(methodName, presetStart) {
|
|
32
32
|
return function(data) {
|
|
33
|
-
const { obj, result, hooked
|
|
33
|
+
const { obj, result, hooked } = data;
|
|
34
34
|
|
|
35
35
|
if (!result?.length || !getPropagatorContext()) {
|
|
36
36
|
return;
|
|
@@ -56,7 +56,9 @@ module.exports = function(core) {
|
|
|
56
56
|
name: `String.prototype.${methodName}`,
|
|
57
57
|
moduleName: 'String',
|
|
58
58
|
methodName: `prototype.${methodName}`,
|
|
59
|
-
context
|
|
59
|
+
get context() {
|
|
60
|
+
return `'${obj}'.${methodName}()`;
|
|
61
|
+
},
|
|
60
62
|
history,
|
|
61
63
|
object: {
|
|
62
64
|
value: obj,
|
|
@@ -69,7 +71,6 @@ module.exports = function(core) {
|
|
|
69
71
|
tags: newTags,
|
|
70
72
|
stacktraceOpts: {
|
|
71
73
|
constructorOpt: hooked,
|
|
72
|
-
prependFrames: [orig]
|
|
73
74
|
},
|
|
74
75
|
source: 'O',
|
|
75
76
|
target: 'R'
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
const { DataflowTag: { WEAK_URL_ENCODED } } = require('@contrast/common');
|
|
19
19
|
const { createFullLengthCopyTags } = require('../../tag-utils');
|
|
20
|
-
const { patchType,
|
|
20
|
+
const { patchType, globalObject: object } = require('../common');
|
|
21
21
|
|
|
22
22
|
module.exports = function(core) {
|
|
23
23
|
const {
|
|
@@ -38,29 +38,26 @@ module.exports = function(core) {
|
|
|
38
38
|
patchType,
|
|
39
39
|
usePerf: 'sync',
|
|
40
40
|
post(data) {
|
|
41
|
-
const { args, result, hooked
|
|
41
|
+
const { args, result, hooked } = data;
|
|
42
42
|
if (!result || !args[0] || !getPropagatorContext()) return;
|
|
43
43
|
|
|
44
44
|
const argInfo = tracker.getData(args[0]);
|
|
45
|
-
|
|
46
45
|
if (!argInfo) return;
|
|
47
46
|
|
|
48
47
|
const resultInfo = tracker.getData(result);
|
|
49
48
|
const history = [argInfo];
|
|
50
49
|
const newTags = createFullLengthCopyTags(argInfo.tags, result.length);
|
|
51
50
|
delete newTags[WEAK_URL_ENCODED];
|
|
52
|
-
|
|
53
51
|
if (!Object.keys(newTags).length) return;
|
|
54
52
|
|
|
55
53
|
const event = createPropagationEvent({
|
|
56
54
|
name,
|
|
57
55
|
moduleName: 'global',
|
|
58
56
|
methodName: 'unescape',
|
|
59
|
-
context
|
|
60
|
-
|
|
61
|
-
value: createObjectLabel('global'),
|
|
62
|
-
tracked: false
|
|
57
|
+
get context() {
|
|
58
|
+
return `unescape('${argInfo.value}')`;
|
|
63
59
|
},
|
|
60
|
+
object,
|
|
64
61
|
result: {
|
|
65
62
|
value: resultInfo ? resultInfo.value : result,
|
|
66
63
|
tracked: true
|
|
@@ -73,18 +70,13 @@ module.exports = function(core) {
|
|
|
73
70
|
removedTags: [WEAK_URL_ENCODED],
|
|
74
71
|
stacktraceOpts: {
|
|
75
72
|
constructorOpt: hooked,
|
|
76
|
-
prependFrames: [orig]
|
|
77
73
|
},
|
|
78
74
|
});
|
|
79
|
-
|
|
80
75
|
if (!event) return;
|
|
81
76
|
|
|
82
|
-
if (resultInfo)
|
|
83
|
-
Object.assign(resultInfo, event);
|
|
84
|
-
}
|
|
77
|
+
if (resultInfo) Object.assign(resultInfo, event);
|
|
85
78
|
|
|
86
79
|
const { extern } = tracker.track(result, event);
|
|
87
|
-
|
|
88
80
|
if (extern) {
|
|
89
81
|
data.result = extern;
|
|
90
82
|
}
|