clarity-js 0.6.43 → 0.7.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/test/core.test.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { assert } from 'chai';
2
2
  import { Browser, Page } from 'playwright';
3
- import { clicks, inputs, launch, markup, node, text } from './helper';
4
- import { Data, decode } from "clarity-decode";
3
+ import { changes, clicks, inputs, launch, markup, node, text } from './helper';
4
+ import { decode } from "clarity-decode";
5
5
 
6
6
  let browser: Browser;
7
7
  let page: Page;
@@ -34,8 +34,11 @@ describe('Core Tests', () => {
34
34
  let password = node(decoded, "attributes.id", "pwd");
35
35
  let search = node(decoded, "attributes.id", "search");
36
36
  let card = node(decoded, "attributes.id", "cardnum");
37
+ let option = text(decoded, "option1");
38
+ let textarea = text(decoded, "textarea");
37
39
  let click = clicks(decoded)[0];
38
40
  let input = inputs(decoded)[0];
41
+ let group = changes(decoded);
39
42
 
40
43
  // Non-sensitive fields continue to pass through with sensitive bits masked off
41
44
  assert.equal(heading, "Thanks for your order #▫▪▪▫▫▫▪▪");
@@ -43,13 +46,24 @@ describe('Core Tests', () => {
43
46
  // Sensitive fields, including input fields, are randomized and masked
44
47
  assert.equal(address, "•••••• ••••• ••••• ••••• ••••• •••••");
45
48
  assert.equal(email.attributes.value, "••••• •••• •••• ••••");
46
- assert.equal(password.attributes.value, "••••• ••••");
47
- assert.equal(search.attributes.value, "hello ▪▫▪▪▪");
48
- assert.equal(card.attributes.value, "▫▫▫▫");
49
+ assert.equal(password.attributes.value, "••••");
50
+ assert.equal(search.attributes.value, "••••• •••• ••••");
51
+ assert.equal(card.attributes.value, "•••••");
52
+ assert.equal(textarea, "••••• •••••");
53
+ assert.equal(option, "• •••••");
49
54
 
50
55
  // Clicked text and input value should be consistent with uber masking configuration
51
56
  assert.equal(click.data.text, "Hello ▪▪▪▫▪");
52
- assert.equal(input.data.value, "query with ▪▪▪▪▫▪▪");
57
+ assert.equal(input.data.value, "••••• •••• •••• ••••");
58
+ assert.equal(group.length, 2);
59
+ // Search change - we should captured mangled input and hash
60
+ assert.equal(group[0].data.type, "search");
61
+ assert.equal(group[0].data.value, "••••• •••• •••• ••••");
62
+ assert.equal(group[0].data.checksum, "4y7m6");
63
+ // Password change - we should capture placholder value and empty hash
64
+ assert.equal(group[1].data.type, "password");
65
+ assert.equal(group[1].data.value, "••••");
66
+ assert.equal(group[1].data.checksum, "");
53
67
  });
54
68
 
55
69
  it('should mask all text in strict mode', async () => {
@@ -63,14 +77,16 @@ describe('Core Tests', () => {
63
77
  let card = node(decoded, "attributes.id", "cardnum");
64
78
  let click = clicks(decoded)[0];
65
79
  let input = inputs(decoded)[0];
80
+ let option = text(decoded, "option1");
66
81
 
67
82
  // All fields are randomized and masked
68
83
  assert.equal(heading, "• ••••• ••••• ••••• ••••• •••••");
69
84
  assert.equal(address, "•••••• ••••• ••••• ••••• ••••• •••••");
70
85
  assert.equal(email.attributes.value, "••••• •••• •••• ••••");
71
- assert.equal(password.attributes.value, "••••• ••••");
86
+ assert.equal(password.attributes.value, "••••");
72
87
  assert.equal(search.attributes.value, "••••• •••• ••••");
73
88
  assert.equal(card.attributes.value, "•••••");
89
+ assert.equal(option, "• •••••");
74
90
 
75
91
  // Clicked text and input value should also be masked in strict mode
76
92
  assert.equal(click.data.text, "••••• •••• ••••");
@@ -88,20 +104,22 @@ describe('Core Tests', () => {
88
104
  let card = node(decoded, "attributes.id", "cardnum");
89
105
  let click = clicks(decoded)[0];
90
106
  let input = inputs(decoded)[0];
107
+ let option = text(decoded, "option1");
91
108
 
92
- // Text flows through unmasked for non-sensitive fields, including input fields
109
+ // Text flows through unmasked for non-sensitive fields, with exception of input fields
93
110
  assert.equal(heading, "Thanks for your order #2AB700GH");
94
111
  assert.equal(address, "1 Microsoft Way, Redmond, WA - 98052");
95
- assert.equal(search.attributes.value, "hello w0rld");
112
+ assert.equal(search.attributes.value, "••••• •••• ••••");
113
+ assert.equal(option, "• •••••");
96
114
 
97
115
  // Sensitive fields are still masked
98
116
  assert.equal(email.attributes.value, "••••• •••• •••• ••••");
99
- assert.equal(password.attributes.value, "••••• ••••");
117
+ assert.equal(password.attributes.value, "••••");
100
118
  assert.equal(card.attributes.value, "•••••");
101
119
 
102
- // Clicked text and input value (non-sensitive) both come through without masking in relaxed mode
120
+ // Clicked text comes through unmasked in relaxed mode but input is still masked
103
121
  assert.equal(click.data.text, "Hello Wor1d");
104
- assert.equal(input.data.value, "query with numb3rs");
122
+ assert.equal(input.data.value, "••••• •••• •••• ••••");
105
123
  });
106
124
 
107
125
  it('should respect mask config even in relaxed mode', async () => {
@@ -114,8 +132,8 @@ describe('Core Tests', () => {
114
132
  // Masked sub-trees continue to stay masked
115
133
  assert.equal(subtree, "••••• •••••");
116
134
 
117
- // Clicked text is masked due to masked configuration while input value is not masked in relaxed mode
135
+ // Clicked text is masked due to masked configuration and input value is also masked
118
136
  assert.equal(click.data.text, "••••• •••• ••••");
119
- assert.equal(input.data.value, "query with numb3rs");
137
+ assert.equal(input.data.value, "••••• •••• •••• ••••");
120
138
  });
121
139
  });
package/test/helper.ts CHANGED
@@ -26,7 +26,11 @@ export async function markup(page: Page, file: string, override: Core.Config = n
26
26
  `));
27
27
  await page.hover("#two");
28
28
  await page.click("#child");
29
- await page.locator('#search').fill('query with numb3rs');
29
+ await page.locator('#search').fill('');
30
+ await page.locator('#search').type('query with numb3rs');
31
+ await page.locator('#pwd').type('p1ssw0rd');
32
+ await page.locator('#eml').fill('');
33
+ await page.locator('#eml').type('hello@world.com');
30
34
  await page.waitForFunction("payloads && payloads.length > 2");
31
35
  return await page.evaluate('payloads');
32
36
  }
@@ -57,6 +61,19 @@ export function inputs(decoded: Data.DecodedPayload[]): Interaction.InputEvent[]
57
61
  return output;
58
62
  }
59
63
 
64
+ export function changes(decoded: Data.DecodedPayload[]): Interaction.ChangeEvent[] {
65
+ let output: Interaction.ChangeEvent[] = [];
66
+ for (let i = decoded.length - 1; i >= 0; i--) {
67
+ if (decoded[i].change) {
68
+ for (let j = 0; j < decoded[i].change.length;j++)
69
+ {
70
+ output.push(decoded[i].change[j]);
71
+ }
72
+ }
73
+ }
74
+ return output;
75
+ }
76
+
60
77
  export function node(decoded: Data.DecodedPayload[], key: string, value: string | number, tag: string = null): Layout.DomData {
61
78
  let sub = null;
62
79
 
@@ -2,6 +2,7 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>Core Tests</title>
5
+ <style>input, textarea, select { margin: 10px; display: block; }</style>
5
6
  </head>
6
7
  <body>
7
8
  <div>
@@ -16,6 +17,11 @@
16
17
  <input type="password" id="pwd" title="Password" maxlength="16" value="passw0rd">
17
18
  <input type="search" id="search" title="Search" value="hello w0rld">
18
19
  <input type="text" id="cardnum" title="CC" value="1234">
20
+ <textarea id="textarea" autocapitalize="off" role="combobox" rows="5" placeholder="" spellcheck="false">Hell0 World</textarea>
21
+ <select id="select" ng-options="origin.code" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false">
22
+ <option id="option1" label="Halifax" value="string:YHZ">Halifax</option>
23
+ <option id="option2" label="Montréal" value="string:YUL" selected="selected">Montréal</option>
24
+ </select>
19
25
  </form>
20
26
  </body>
21
27
  </html>
package/types/core.d.ts CHANGED
@@ -4,7 +4,7 @@ type TaskFunction = () => Promise<void>;
4
4
  type TaskResolve = () => void;
5
5
  type UploadCallback = (data: string) => void;
6
6
  type Region = [number /* RegionId */, string /* Query Selector */];
7
- type Fraud = [number /* FraudId */, string /* Query Selector */];
7
+ type Checksum = [number /* FraudId */, string /* Query Selector */];
8
8
  export type Extract = ExtractSource /* Extraction Source */ | number /* Extract Id */ | string | string[] /* Hash or Query Selector or String Token */;
9
9
 
10
10
  /* Enum */
@@ -123,12 +123,14 @@ export interface Config {
123
123
  lean?: boolean;
124
124
  track?: boolean;
125
125
  content?: boolean;
126
+ drop?: string[];
126
127
  mask?: string[];
127
128
  unmask?: string[];
128
129
  regions?: Region[];
129
130
  extract?: Extract[];
130
131
  cookies?: string[];
131
- fraud?: Fraud[];
132
+ fraud?: boolean;
133
+ checksum?: Checksum[];
132
134
  report?: string;
133
135
  upload?: string | UploadCallback;
134
136
  fallback?: string;
package/types/data.d.ts CHANGED
@@ -62,7 +62,8 @@ export const enum Event {
62
62
  Clipboard = 38,
63
63
  Submit = 39,
64
64
  Extract = 40,
65
- Fraud = 41
65
+ Fraud = 41,
66
+ Change = 42
66
67
  }
67
68
 
68
69
  export const enum Metric {
@@ -98,6 +99,9 @@ export const enum Metric {
98
99
  SinglePage = 29,
99
100
  UsedMemory = 30,
100
101
  Iframed = 31,
102
+ MaxTouchPoints = 32,
103
+ HardwareConcurrency = 33,
104
+ DeviceMemory = 34
101
105
  }
102
106
 
103
107
  export const enum Dimension {
@@ -126,7 +130,9 @@ export const enum Dimension {
126
130
  Platform = 22,
127
131
  PlatformVersion = 23,
128
132
  Brand = 24,
129
- Model = 25
133
+ Model = 25,
134
+ DevicePixelRatio = 26,
135
+ ConnectionType = 27
130
136
  }
131
137
 
132
138
  export const enum Check {
@@ -207,7 +213,8 @@ export const enum Setting {
207
213
  UploadFactor = 3, // Slow down sequence by specified factor
208
214
  MinUploadDelay = 100, // Minimum time before we are ready to flush events to the server
209
215
  MaxUploadDelay = 30 * Time.Second, // Do flush out payload once every 30s,
210
- ExtractLimit = 10000 // Do not extract more than 10000 characters
216
+ ExtractLimit = 10000, // Do not extract more than 10000 characters
217
+ ChecksumPrecision = 24 // n-bit integer to represent token hash
211
218
  }
212
219
 
213
220
  export const enum Character {
@@ -234,6 +241,7 @@ export const enum Constant {
234
241
  Space = " ",
235
242
  Expires = "expires=",
236
243
  Domain = "domain=",
244
+ Dropped = "*na*",
237
245
  Comma = ",",
238
246
  Dot = ".",
239
247
  Semicolon = ";",
@@ -20,5 +20,5 @@ export interface LogData {
20
20
  export interface FraudData {
21
21
  id: number;
22
22
  target: number;
23
- hash: string;
23
+ checksum: string;
24
24
  }
@@ -12,6 +12,7 @@ export const enum BrowsingContext {
12
12
 
13
13
  export const enum Setting {
14
14
  LookAhead = 500, // 500ms
15
+ InputLookAhead = 1000, // 1s
15
16
  Distance = 20, // 20 pixels
16
17
  Interval = 25, // 25 milliseconds
17
18
  TimelineSpan = 2 * Time.Second, // 2 seconds
@@ -54,6 +55,12 @@ export interface SubmitState {
54
55
  data: SubmitData;
55
56
  }
56
57
 
58
+ export interface ChangeState {
59
+ time: number;
60
+ event: number;
61
+ data: ChangeData;
62
+ }
63
+
57
64
  export interface InputState {
58
65
  time: number;
59
66
  event: number;
@@ -76,6 +83,13 @@ export interface TimelineData {
76
83
  context: number;
77
84
  }
78
85
 
86
+ export interface ChangeData {
87
+ target: Target;
88
+ type: string;
89
+ value: string;
90
+ checksum: string;
91
+ }
92
+
79
93
  export interface InputData {
80
94
  target: Target;
81
95
  value: string;
package/types/layout.d.ts CHANGED
@@ -30,8 +30,9 @@ export const enum RegionVisibility {
30
30
 
31
31
  export const enum Mask {
32
32
  Text = "address,password,contact",
33
- Input = "password,secret,pass,social,ssn,name,code,dob,cell,mob,contact,hidden,account,cvv,ccv,email,tel,phone,address,addr,card,zip",
34
- Disable = "radio,checkbox,range,button,reset,submit"
33
+ Disable = "radio,checkbox,range,button,reset,submit",
34
+ Exclude = "password,secret,pass,social,ssn,code,hidden",
35
+ Tags = "INPUT,SELECT,TEXTAREA"
35
36
  }
36
37
 
37
38
  export const enum Constant {