clarity-js 0.6.40 → 0.6.42
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/build/clarity.js +508 -504
- package/build/clarity.min.js +1 -1
- package/build/clarity.module.js +508 -504
- package/package.json +1 -1
- package/src/core/config.ts +2 -1
- package/src/core/version.ts +1 -1
- package/src/data/upload.ts +6 -2
- package/src/layout/dom.ts +6 -9
- package/test/core.test.ts +11 -5
- package/test/html/core.html +1 -0
- package/types/core.d.ts +1 -0
- package/types/data.d.ts +3 -2
package/package.json
CHANGED
package/src/core/config.ts
CHANGED
package/src/core/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
let version = "0.6.
|
|
1
|
+
let version = "0.6.42";
|
|
2
2
|
export default version;
|
package/src/data/upload.ts
CHANGED
|
@@ -242,8 +242,8 @@ function delay(): number {
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
function response(payload: string): void {
|
|
245
|
-
let
|
|
246
|
-
switch (
|
|
245
|
+
let parts = payload && payload.length > 0 ? payload.split(" ") : [Constant.Empty];
|
|
246
|
+
switch (parts[0]) {
|
|
247
247
|
case Constant.End:
|
|
248
248
|
// Clear out session storage and end the session so we can start fresh the next time
|
|
249
249
|
limit.trigger(Check.Server);
|
|
@@ -252,5 +252,9 @@ function response(payload: string): void {
|
|
|
252
252
|
// Upgrade current session to send back playback information
|
|
253
253
|
clarity.upgrade(Constant.Auto);
|
|
254
254
|
break;
|
|
255
|
+
case Constant.Action:
|
|
256
|
+
// Invoke action callback, if configured and has a valid value
|
|
257
|
+
if (config.action && parts.length > 1) { config.action(parts[1]); }
|
|
258
|
+
break;
|
|
255
259
|
}
|
|
256
260
|
}
|
package/src/layout/dom.ts
CHANGED
|
@@ -92,8 +92,7 @@ export function add(node: Node, parent: Node, data: NodeInfo, source: Source): v
|
|
|
92
92
|
let regionId = region.exists(node) ? id : null;
|
|
93
93
|
let fragmentId = null;
|
|
94
94
|
let fraudId = fraudMap.has(node) ? fraudMap.get(node) : null;
|
|
95
|
-
let privacyId = config.content ? Privacy.Sensitive : Privacy.
|
|
96
|
-
|
|
95
|
+
let privacyId = config.content ? Privacy.Sensitive : Privacy.TextImage
|
|
97
96
|
if (parentId >= 0 && values[parentId]) {
|
|
98
97
|
parentValue = values[parentId];
|
|
99
98
|
parentValue.children.push(id);
|
|
@@ -243,21 +242,19 @@ function privacy(node: Node, value: NodeValue, parent: NodeValue): void {
|
|
|
243
242
|
let tags : string[] = [Constant.StyleTag, Constant.TitleTag, Constant.SvgStyle];
|
|
244
243
|
metadata.privacy = tags.includes(pTag) || override.some(x => pSelector.indexOf(x) >= 0) ? Privacy.None : current;
|
|
245
244
|
break;
|
|
246
|
-
case Constant.Type in attributes:
|
|
247
|
-
// If this node has an explicit type assigned to it, go through masking rules to determine right privacy setting
|
|
248
|
-
metadata.privacy = inspect(attributes[Constant.Type], maskInput, metadata);
|
|
249
|
-
break;
|
|
250
245
|
case tag === Constant.InputTag && current === Privacy.None:
|
|
251
246
|
// If even default privacy setting is to not mask, we still scan through input fields for any sensitive information
|
|
252
247
|
let field: string = Constant.Empty;
|
|
253
248
|
Object.keys(attributes).forEach(x => field += attributes[x].toLowerCase());
|
|
254
249
|
metadata.privacy = inspect(field, maskInput, metadata);
|
|
255
250
|
break;
|
|
256
|
-
case
|
|
251
|
+
case tag === Constant.InputTag && current === Privacy.Sensitive:
|
|
257
252
|
// Look through class names to aggressively mask content
|
|
258
253
|
metadata.privacy = inspect(attributes[Constant.Class], maskText, metadata);
|
|
259
|
-
// If
|
|
260
|
-
metadata.privacy
|
|
254
|
+
// If this node has an explicit type assigned to it, go through masking rules to determine right privacy setting
|
|
255
|
+
metadata.privacy = inspect(attributes[Constant.Type], maskInput, metadata);
|
|
256
|
+
// If it's a button or an input option, make an exception to disable masking in sensitive mode
|
|
257
|
+
metadata.privacy = maskDisable.indexOf(attributes[Constant.Type]) >= 0 ? Privacy.None : metadata.privacy;
|
|
261
258
|
break;
|
|
262
259
|
case current === Privacy.Sensitive:
|
|
263
260
|
// In a mode where we mask sensitive information by default, look through class names to aggressively mask content
|
package/test/core.test.ts
CHANGED
|
@@ -33,21 +33,23 @@ describe('Core Tests', () => {
|
|
|
33
33
|
let email = node(decoded, "attributes.id", "eml");
|
|
34
34
|
let password = node(decoded, "attributes.id", "pwd");
|
|
35
35
|
let search = node(decoded, "attributes.id", "search");
|
|
36
|
+
let card = node(decoded, "attributes.id", "cardnum");
|
|
36
37
|
let click = clicks(decoded)[0];
|
|
37
38
|
let input = inputs(decoded)[0];
|
|
38
39
|
|
|
39
40
|
// Non-sensitive fields continue to pass through with sensitive bits masked off
|
|
40
|
-
assert.equal(heading, "Thanks for your order
|
|
41
|
+
assert.equal(heading, "Thanks for your order #▫▪▪▫▫▫▪▪");
|
|
41
42
|
|
|
42
43
|
// Sensitive fields, including input fields, are randomized and masked
|
|
43
44
|
assert.equal(address, "•••••• ••••• ••••• ••••• ••••• •••••");
|
|
44
45
|
assert.equal(email.attributes.value, "••••• •••• •••• ••••");
|
|
45
46
|
assert.equal(password.attributes.value, "••••• ••••");
|
|
46
|
-
assert.equal(search.attributes.value, "hello
|
|
47
|
+
assert.equal(search.attributes.value, "hello ▪▫▪▪▪");
|
|
48
|
+
assert.equal(card.attributes.value, "▫▫▫▫");
|
|
47
49
|
|
|
48
50
|
// Clicked text and input value should be consistent with uber masking configuration
|
|
49
|
-
assert.equal(click.data.text, "Hello
|
|
50
|
-
assert.equal(input.data.value, "query with
|
|
51
|
+
assert.equal(click.data.text, "Hello ▪▪▪▫▪");
|
|
52
|
+
assert.equal(input.data.value, "query with ▪▪▪▪▫▪▪");
|
|
51
53
|
});
|
|
52
54
|
|
|
53
55
|
it('should mask all text in strict mode', async () => {
|
|
@@ -58,6 +60,7 @@ describe('Core Tests', () => {
|
|
|
58
60
|
let email = node(decoded, "attributes.id", "eml");
|
|
59
61
|
let password = node(decoded, "attributes.id", "pwd");
|
|
60
62
|
let search = node(decoded, "attributes.id", "search");
|
|
63
|
+
let card = node(decoded, "attributes.id", "cardnum");
|
|
61
64
|
let click = clicks(decoded)[0];
|
|
62
65
|
let input = inputs(decoded)[0];
|
|
63
66
|
|
|
@@ -67,13 +70,14 @@ describe('Core Tests', () => {
|
|
|
67
70
|
assert.equal(email.attributes.value, "••••• •••• •••• ••••");
|
|
68
71
|
assert.equal(password.attributes.value, "••••• ••••");
|
|
69
72
|
assert.equal(search.attributes.value, "••••• •••• ••••");
|
|
73
|
+
assert.equal(card.attributes.value, "•••••");
|
|
70
74
|
|
|
71
75
|
// Clicked text and input value should also be masked in strict mode
|
|
72
76
|
assert.equal(click.data.text, "••••• •••• ••••");
|
|
73
77
|
assert.equal(input.data.value, "••••• •••• •••• ••••");
|
|
74
78
|
});
|
|
75
79
|
|
|
76
|
-
it('should unmask
|
|
80
|
+
it('should unmask non-sensitive text in relaxed mode', async () => {
|
|
77
81
|
let encoded: string[] = await markup(page, "core.html", { unmask: ["body"] });
|
|
78
82
|
let decoded = encoded.map(x => decode(x));
|
|
79
83
|
let heading = text(decoded, "one");
|
|
@@ -81,6 +85,7 @@ describe('Core Tests', () => {
|
|
|
81
85
|
let email = node(decoded, "attributes.id", "eml");
|
|
82
86
|
let password = node(decoded, "attributes.id", "pwd");
|
|
83
87
|
let search = node(decoded, "attributes.id", "search");
|
|
88
|
+
let card = node(decoded, "attributes.id", "cardnum");
|
|
84
89
|
let click = clicks(decoded)[0];
|
|
85
90
|
let input = inputs(decoded)[0];
|
|
86
91
|
|
|
@@ -92,6 +97,7 @@ describe('Core Tests', () => {
|
|
|
92
97
|
// Sensitive fields are still masked
|
|
93
98
|
assert.equal(email.attributes.value, "••••• •••• •••• ••••");
|
|
94
99
|
assert.equal(password.attributes.value, "••••• ••••");
|
|
100
|
+
assert.equal(card.attributes.value, "•••••");
|
|
95
101
|
|
|
96
102
|
// Clicked text and input value (non-sensitive) both come through without masking in relaxed mode
|
|
97
103
|
assert.equal(click.data.text, "Hello Wor1d");
|
package/test/html/core.html
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
<input type="email" id="eml" title="Email" value="random@email.test">
|
|
16
16
|
<input type="password" id="pwd" title="Password" maxlength="16" value="passw0rd">
|
|
17
17
|
<input type="search" id="search" title="Search" value="hello w0rld">
|
|
18
|
+
<input type="text" id="cardnum" title="CC" value="1234">
|
|
18
19
|
</form>
|
|
19
20
|
</body>
|
|
20
21
|
</html>
|
package/types/core.d.ts
CHANGED
package/types/data.d.ts
CHANGED
|
@@ -244,12 +244,13 @@ export const enum Constant {
|
|
|
244
244
|
Pipe = "|",
|
|
245
245
|
End = "END",
|
|
246
246
|
Upgrade = "UPGRADE",
|
|
247
|
+
Action = "ACTION",
|
|
247
248
|
UserId = "userId",
|
|
248
249
|
SessionId = "sessionId",
|
|
249
250
|
PageId = "pageId",
|
|
250
251
|
Mask = "•", // Placeholder character for explicitly masked content
|
|
251
|
-
Digit = "
|
|
252
|
-
Letter = "
|
|
252
|
+
Digit = "▫", // Placeholder character for digits
|
|
253
|
+
Letter = "▪", // Placeholder character for letters
|
|
253
254
|
SessionStorage = "sessionStorage",
|
|
254
255
|
Cookie = "cookie",
|
|
255
256
|
Navigation = "navigation",
|