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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clarity-js",
3
- "version": "0.6.40",
3
+ "version": "0.6.42",
4
4
  "description": "An analytics library that uses web page interactions to generate aggregated insights",
5
5
  "author": "Microsoft Corp.",
6
6
  "license": "MIT",
@@ -15,7 +15,8 @@ let config: Config = {
15
15
  report: null,
16
16
  upload: null,
17
17
  fallback: null,
18
- upgrade: null
18
+ upgrade: null,
19
+ action: null
19
20
  };
20
21
 
21
22
  export default config;
@@ -1,2 +1,2 @@
1
- let version = "0.6.40";
1
+ let version = "0.6.42";
2
2
  export default version;
@@ -242,8 +242,8 @@ function delay(): number {
242
242
  }
243
243
 
244
244
  function response(payload: string): void {
245
- let key = payload && payload.length > 0 ? payload.split(" ")[0] : Constant.Empty;
246
- switch (key) {
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.Text
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 current === Privacy.Sensitive && tag === Constant.InputTag:
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 it's a button or an input option, make an exception to disable masking
260
- metadata.privacy = maskDisable.indexOf(attributes[Constant.Type]) >= 0 ? Privacy.None : current;
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 all text in relaxed mode', async () => {
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");
@@ -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
@@ -133,6 +133,7 @@ export interface Config {
133
133
  upload?: string | UploadCallback;
134
134
  fallback?: string;
135
135
  upgrade?: (key: string) => void;
136
+ action?: (key: string) => void;
136
137
  }
137
138
 
138
139
  export const enum Constant {
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 = "", // Placeholder character for digits
252
- Letter = "", // Placeholder character for letters
252
+ Digit = "", // Placeholder character for digits
253
+ Letter = "", // Placeholder character for letters
253
254
  SessionStorage = "sessionStorage",
254
255
  Cookie = "cookie",
255
256
  Navigation = "navigation",