devicer.js 1.0.9 → 1.0.11

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": "devicer.js",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Open-Source Digital Fingerprinting Middleware",
5
5
  "main": "src/main.js",
6
6
  "scripts": {
@@ -1,73 +1,104 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateConfidence = void 0;
3
+ exports.calculateConfidence = exports.compareDatasets = exports.compareArrays = void 0;
4
4
  const tlsh_1 = require("./tlsh");
5
- function compareArrays(arr1, arr2) {
5
+ function compareArrays(arr1, arr2, max_depth = 5) {
6
6
  let fields = 0;
7
7
  let matches = 0;
8
- const maxLength = Math.max(arr1.length, arr2.length);
8
+ // Ensure max_depth is not exceeded
9
+ if (max_depth <= 0) {
10
+ throw new Error("Max depth exceeded");
11
+ }
12
+ // Sort arrays to ensure consistent comparison
13
+ const sortedArr1 = arr1.map((item) => JSON.stringify(item)).sort().map((item) => {
14
+ try {
15
+ return JSON.parse(item);
16
+ }
17
+ catch (e) {
18
+ return undefined;
19
+ }
20
+ });
21
+ const sortedArr2 = arr2.map((item) => JSON.stringify(item)).sort().map((item) => {
22
+ try {
23
+ return JSON.parse(item);
24
+ }
25
+ catch (e) {
26
+ return undefined;
27
+ }
28
+ });
29
+ const maxLength = Math.min(arr1.length, arr2.length);
9
30
  for (let i = 0; i < maxLength; i++) {
10
- if (arr1[i] !== undefined && arr2[i] !== undefined) {
11
- fields++;
12
- if (Array.isArray(arr1[i]) && Array.isArray(arr2[i])) {
13
- const subData = compareArrays(arr1[i], arr2[i]);
14
- fields += subData[0] - 1; // Subtract 1 for the index itself
15
- matches += subData[1];
16
- }
17
- else if ((typeof arr1[i] == "object" && arr1[i]) &&
18
- (typeof arr2[i] == "object" && arr2[i])) {
19
- const subData = compareDatasets(arr1[i], arr2[i]);
20
- fields += subData[0] - 1; // Subtract 1 for the index itself
21
- matches += subData[1];
22
- }
23
- else if (arr1[i] === arr2[i]) {
24
- matches++;
25
- }
31
+ fields++;
32
+ if (Array.isArray(sortedArr1[i]) && Array.isArray(sortedArr2[i])) {
33
+ const subData = compareArrays(sortedArr1[i], sortedArr2[i], max_depth - 1);
34
+ fields += subData[0] - 1; // Subtract 1 for the index itself
35
+ matches += subData[1];
36
+ }
37
+ else if ((typeof sortedArr1[i] == "object" && sortedArr1[i]) &&
38
+ (typeof sortedArr2[i] == "object" && sortedArr2[i])) {
39
+ const subData = compareDatasets(sortedArr1[i], sortedArr2[i], max_depth - 1);
40
+ fields += subData[0] - 1; // Subtract 1 for the index itself
41
+ matches += subData[1];
42
+ }
43
+ if (arr1[i] === arr2[i]) {
44
+ matches++;
26
45
  }
27
46
  }
28
47
  return [fields, matches];
29
48
  }
30
- function compareDatasets(data1, data2) {
49
+ exports.compareArrays = compareArrays;
50
+ function compareDatasets(data1, data2, max_depth = 5) {
31
51
  let fields = 0;
32
52
  let matches = 0;
53
+ // Ensure max_depth is not exceeded
54
+ if (max_depth <= 0) {
55
+ throw new Error("Max depth exceeded");
56
+ }
33
57
  for (const key in data1) {
34
58
  if (data1[key] !== undefined && data2[key] !== undefined) {
35
59
  fields++;
36
60
  if ((typeof data1[key] == "object" && data1[key]) &&
37
61
  (typeof data2[key] == "object" && data2[key])) {
38
- const subData = compareDatasets(data1[key], data2[key]);
62
+ const subData = compareDatasets(data1[key], data2[key], max_depth - 1);
39
63
  fields += subData[0] - 1; // Subtract 1 for the key itself
40
64
  matches += subData[1];
41
65
  }
42
66
  else if (Array.isArray(data1[key]) && Array.isArray(data2[key])) {
43
- const subData = compareArrays(data1[key], data2[key]);
67
+ const subData = compareArrays(data1[key], data2[key], max_depth - 1);
44
68
  fields += subData[0] - 1; // Subtract 1 for the key itself
45
69
  matches += subData[1];
46
70
  }
47
- if (data1[key] == data2[key]) {
71
+ else if (data1[key] == data2[key]) {
48
72
  matches++;
49
73
  }
50
74
  }
51
75
  }
52
76
  return [fields, matches];
53
77
  }
78
+ exports.compareDatasets = compareDatasets;
54
79
  function calculateConfidence(data1, data2) {
55
- // Compare how many fields are the same in both datasets
56
- const [fields, matches] = compareDatasets(data1, data2);
57
- if (fields === 0 || matches === 0) {
58
- return 0;
80
+ try {
81
+ // Compare how many fields are the same in both datasets
82
+ const [fields, matches] = compareDatasets(data1, data2);
83
+ if (fields === 0 || matches === 0) {
84
+ return 0;
85
+ }
86
+ // Calculate the hash for each user data
87
+ const hash1 = (0, tlsh_1.getHash)(JSON.stringify(data1));
88
+ const hash2 = (0, tlsh_1.getHash)(JSON.stringify(data2));
89
+ // Compare the hashes to get their difference
90
+ const differenceScore = (0, tlsh_1.compareHashes)(hash1, hash2);
91
+ const inverseMatchScore = 1 - (matches / fields);
92
+ const x = 1.3 * differenceScore * inverseMatchScore;
93
+ if (inverseMatchScore === 0 || differenceScore === 0) {
94
+ return 100;
95
+ }
96
+ const confidenceScore = 100 / (1 + Math.E ** (-4.5 + (0.3 * x)));
97
+ return confidenceScore;
59
98
  }
60
- // Calculate the hash for each user data
61
- const hash1 = (0, tlsh_1.getHash)(JSON.stringify(data1));
62
- const hash2 = (0, tlsh_1.getHash)(JSON.stringify(data2));
63
- // Compare the hashes to get their difference
64
- const differenceScore = (0, tlsh_1.compareHashes)(hash1, hash2);
65
- const inverseMatchScore = 1 - (matches / fields);
66
- const x = 1.3 * differenceScore * inverseMatchScore;
67
- if (inverseMatchScore === 0 || differenceScore === 0) {
68
- return 100;
99
+ catch (error) {
100
+ console.error("Error calculating confidence:", error);
101
+ return 0; // Return 0 if an error occurs during comparison
69
102
  }
70
- const confidenceScore = 100 / (1 + Math.E ** (-4.5 + (0.3 * x)));
71
- return confidenceScore;
72
103
  }
73
104
  exports.calculateConfidence = calculateConfidence;
@@ -1,39 +1,85 @@
1
- import { getHash, compareHashes } from "./tlsh";
1
+ import { compareHashes, getHash } from "./tlsh";
2
2
  import { FPDataSet } from "../types/data";
3
3
 
4
- function compareArrays(arr1: any[], arr2: any[]): [number, number] {
4
+ export function compareArrays(
5
+ arr1: any[],
6
+ arr2: any[],
7
+ max_depth: number = 5,
8
+ ): [number, number] {
5
9
  let fields = 0;
6
10
  let matches = 0;
7
- const maxLength = Math.max(arr1.length, arr2.length);
8
- for (let i = 0; i < maxLength; i++) {
9
- if (arr1[i] !== undefined && arr2[i] !== undefined) {
10
- fields++;
11
- if (Array.isArray(arr1[i]) && Array.isArray(arr2[i])) {
12
- const subData = compareArrays(arr1[i], arr2[i]);
13
- fields += subData[0] - 1; // Subtract 1 for the index itself
14
- matches += subData[1];
15
- }
16
-
17
- else if (
18
- (typeof arr1[i] == "object" && arr1[i]) &&
19
- (typeof arr2[i] == "object" && arr2[i])
20
- ) {
21
- const subData = compareDatasets(arr1[i] as FPDataSet, arr2[i] as FPDataSet);
22
- fields += subData[0] - 1; // Subtract 1 for the index itself
23
- matches += subData[1];
11
+
12
+ // Ensure max_depth is not exceeded
13
+ if (max_depth <= 0) {
14
+ throw new Error("Max depth exceeded");
15
+ }
16
+
17
+ // Sort arrays to ensure consistent comparison
18
+ const sortedArr1 = arr1.map((item) => JSON.stringify(item)).sort().map(
19
+ (item) => {
20
+ try {
21
+ return JSON.parse(item);
22
+ } catch (e) {
23
+ return undefined;
24
24
  }
25
-
26
- if (arr1[i] === arr2[i]) {
27
- matches++;
25
+ },
26
+ );
27
+ const sortedArr2 = arr2.map((item) => JSON.stringify(item)).sort().map(
28
+ (item) => {
29
+ try {
30
+ return JSON.parse(item);
31
+ } catch (e) {
32
+ return undefined;
28
33
  }
34
+ },
35
+ );
36
+
37
+ const maxLength = Math.min(arr1.length, arr2.length);
38
+ for (let i = 0; i < maxLength; i++) {
39
+ fields++;
40
+ if (Array.isArray(sortedArr1[i]) && Array.isArray(sortedArr2[i])) {
41
+ const subData = compareArrays(
42
+ sortedArr1[i],
43
+ sortedArr2[i],
44
+ max_depth - 1,
45
+ );
46
+ fields += subData[0] - 1; // Subtract 1 for the index itself
47
+ matches += subData[1];
48
+ }
49
+
50
+ else if (
51
+ (typeof sortedArr1[i] == "object" && sortedArr1[i]) &&
52
+ (typeof sortedArr2[i] == "object" && sortedArr2[i])
53
+ ) {
54
+ const subData = compareDatasets(
55
+ sortedArr1[i] as FPDataSet,
56
+ sortedArr2[i] as FPDataSet,
57
+ max_depth - 1,
58
+ );
59
+ fields += subData[0] - 1; // Subtract 1 for the index itself
60
+ matches += subData[1];
61
+ }
62
+
63
+ if (arr1[i] === arr2[i]) {
64
+ matches++;
29
65
  }
30
66
  }
31
67
  return [fields, matches];
32
68
  }
33
69
 
34
- function compareDatasets(data1: FPDataSet, data2: FPDataSet): [number, number] {
70
+ export function compareDatasets(
71
+ data1: FPDataSet,
72
+ data2: FPDataSet,
73
+ max_depth: number = 5,
74
+ ): [number, number] {
35
75
  let fields = 0;
36
76
  let matches = 0;
77
+
78
+ // Ensure max_depth is not exceeded
79
+ if (max_depth <= 0) {
80
+ throw new Error("Max depth exceeded");
81
+ }
82
+
37
83
  for (const key in data1) {
38
84
  if (data1[key] !== undefined && data2[key] !== undefined) {
39
85
  fields++;
@@ -41,18 +87,22 @@ function compareDatasets(data1: FPDataSet, data2: FPDataSet): [number, number] {
41
87
  (typeof data1[key] == "object" && data1[key]) &&
42
88
  (typeof data2[key] == "object" && data2[key])
43
89
  ) {
44
- const subData = compareDatasets(data1[key] as FPDataSet, data2[key] as FPDataSet);
90
+ const subData = compareDatasets(
91
+ data1[key] as FPDataSet,
92
+ data2[key] as FPDataSet,
93
+ max_depth - 1,
94
+ );
45
95
  fields += subData[0] - 1; // Subtract 1 for the key itself
46
96
  matches += subData[1];
47
97
  }
48
-
98
+
49
99
  else if (Array.isArray(data1[key]) && Array.isArray(data2[key])) {
50
- const subData = compareArrays(data1[key], data2[key]);
100
+ const subData = compareArrays(data1[key], data2[key], max_depth - 1);
51
101
  fields += subData[0] - 1; // Subtract 1 for the key itself
52
102
  matches += subData[1];
53
103
  }
54
104
 
55
- if (data1[key] == data2[key]) {
105
+ else if (data1[key] == data2[key]) {
56
106
  matches++;
57
107
  }
58
108
  }
@@ -60,26 +110,34 @@ function compareDatasets(data1: FPDataSet, data2: FPDataSet): [number, number] {
60
110
  return [fields, matches];
61
111
  }
62
112
 
63
- export function calculateConfidence(data1: FPDataSet, data2: FPDataSet): number {
64
- // Compare how many fields are the same in both datasets
65
- const [fields, matches] = compareDatasets(data1, data2);
113
+ export function calculateConfidence(
114
+ data1: FPDataSet,
115
+ data2: FPDataSet,
116
+ ): number {
117
+ try {
118
+ // Compare how many fields are the same in both datasets
119
+ const [fields, matches] = compareDatasets(data1, data2);
66
120
 
67
- if (fields === 0 || matches === 0) {
68
- return 0;
69
- }
121
+ if (fields === 0 || matches === 0) {
122
+ return 0;
123
+ }
70
124
 
71
- // Calculate the hash for each user data
72
- const hash1 = getHash(JSON.stringify(data1));
73
- const hash2 = getHash(JSON.stringify(data2));
125
+ // Calculate the hash for each user data
126
+ const hash1 = getHash(JSON.stringify(data1));
127
+ const hash2 = getHash(JSON.stringify(data2));
74
128
 
75
- // Compare the hashes to get their difference
76
- const differenceScore = compareHashes(hash1, hash2);
129
+ // Compare the hashes to get their difference
130
+ const differenceScore = compareHashes(hash1, hash2);
77
131
 
78
- const inverseMatchScore = 1 - (matches / fields);
79
- const x = 1.3 * differenceScore * inverseMatchScore
80
- if (inverseMatchScore === 0 || differenceScore === 0) {
81
- return 100;
132
+ const inverseMatchScore = 1 - (matches / fields);
133
+ const x = 1.3 * differenceScore * inverseMatchScore;
134
+ if (inverseMatchScore === 0 || differenceScore === 0) {
135
+ return 100;
136
+ }
137
+ const confidenceScore = 100 / (1 + Math.E ** (-4.5 + (0.3 * x)));
138
+ return confidenceScore;
139
+ } catch (error) {
140
+ console.error("Error calculating confidence:", error);
141
+ return 0; // Return 0 if an error occurs during comparison
82
142
  }
83
- const confidenceScore = 100 / (1 + Math.E ** (-4.5 + (0.3 * x)));
84
- return confidenceScore;
85
- }
143
+ }
package/src/main.js CHANGED
@@ -1,5 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateConfidence = void 0;
3
+ exports.calculateConfidence = exports.compareDatasets = exports.compareArrays = void 0;
4
4
  const confidence_1 = require("./libs/confidence");
5
+ Object.defineProperty(exports, "compareArrays", { enumerable: true, get: function () { return confidence_1.compareArrays; } });
6
+ Object.defineProperty(exports, "compareDatasets", { enumerable: true, get: function () { return confidence_1.compareDatasets; } });
5
7
  Object.defineProperty(exports, "calculateConfidence", { enumerable: true, get: function () { return confidence_1.calculateConfidence; } });
package/src/main.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { FPUserDataSet, FPDataSet } from "./types/data";
2
- import { calculateConfidence } from "./libs/confidence";
2
+ import { compareArrays, compareDatasets, calculateConfidence } from "./libs/confidence";
3
3
 
4
- export { type FPUserDataSet, type FPDataSet, calculateConfidence };
4
+ export { type FPUserDataSet, type FPDataSet, compareArrays, compareDatasets, calculateConfidence };
@@ -0,0 +1,92 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { compareArrays, compareDatasets } from "../src/libs/confidence";
3
+
4
+ const sampleData1 = {"userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0","platform":"Win32","timezone":"America/Chicago","language":"en-US","languages":["en-US","en","es","la"],"cookieEnabled":true,"doNotTrack":"1","hardwareConcurrency":8,"deviceMemory":8,"product":"Gecko","productSub":"20030107","vendor":"Google Inc.","vendorSub":"unknown","appName":"Netscape","appVersion":"5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0","appCodeName":"Mozilla","appMinorVersion":"unknown","buildID":"unknown","plugins":[{"name":"PDF Viewer","description":"Portable Document Format"},{"name":"Chrome PDF Viewer","description":"Portable Document Format"},{"name":"Chromium PDF Viewer","description":"Portable Document Format"},{"name":"Microsoft Edge PDF Viewer","description":"Portable Document Format"},{"name":"WebKit built-in PDF","description":"Portable Document Format"}],"mimeTypes":[{"type":"application/pdf","suffixes":"pdf","description":"Portable Document Format"},{"type":"text/pdf","suffixes":"pdf","description":"Portable Document Format"}],"screen":{"width":1920,"height":1080,"colorDepth":24,"pixelDepth":24,"orientation":{"type":"landscape-primary","angle":0}},"highEntropyValues":{"architecture":"x86","bitness":"64","brands":[{"brand":"Not)A;Brand","version":"8"},{"brand":"Chromium","version":"138"},{"brand":"Microsoft Edge","version":"138"}],"mobile":false,"model":"","platform":"Windows","platformVersion":"19.0.0","uaFullVersion":"138.0.3351.34"}};
5
+
6
+ const sampleData2 = {"userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36","platform":"Win32","timezone":"America/Chicago","language":"en-US","languages":["en-US","en"],"cookieEnabled":true,"hardwareConcurrency":16,"deviceMemory":8,"product":"Gecko","productSub":"20030107","vendor":"Google Inc.","vendorSub":"unknown","appName":"Netscape","appVersion":"5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36","appCodeName":"Mozilla","appMinorVersion":"unknown","buildID":"unknown","plugins":[{"name":"PDF Viewer","description":"Portable Document Format"},{"name":"Chrome PDF Viewer","description":"Portable Document Format"},{"name":"Chromium PDF Viewer","description":"Portable Document Format"},{"name":"Microsoft Edge PDF Viewer","description":"Portable Document Format"},{"name":"WebKit built-in PDF","description":"Portable Document Format"}],"mimeTypes":[{"type":"application/pdf","suffixes":"pdf","description":"Portable Document Format"},{"type":"text/pdf","suffixes":"pdf","description":"Portable Document Format"}],"screen":{"width":1920,"height":1080,"colorDepth":24,"pixelDepth":24,"orientation":{"type":"landscape-primary","angle":0}},"highEntropyValues":{"architecture":"x86","bitness":"64","brands":[{"brand":"Google Chrome","version":"137"},{"brand":"Chromium","version":"137"},{"brand":"Not/A)Brand","version":"24"}],"mobile":false,"model":"","platform":"Windows","platformVersion":"19.0.0","uaFullVersion":"137.0.7151.119"}};
7
+
8
+ describe("Array Comparison", () => {
9
+ it("should compare two identical arrays", () => {
10
+ const arr1 = [1, 2, 3];
11
+ const arr2 = [1, 2, 3];
12
+ const result = compareArrays(arr1, arr2);
13
+ console.log("Result:", result);
14
+ expect(result).toEqual([3, 3]); // 3 fields, 3 matches
15
+ });
16
+
17
+ it("should compare two different arrays", () => {
18
+ const arr1 = [1, 2, 3];
19
+ const arr2 = [3, 1, 4];
20
+ const result = compareArrays(arr1, arr2);
21
+ console.log("Result:", result);
22
+ expect(result).toEqual([3, 0]); // 3 fields, 0 matches
23
+ });
24
+
25
+ it("should handle nested arrays", () => {
26
+ const arr1 = [1, [2, 3], 4];
27
+ const arr2 = [1, [2, 3], 5];
28
+ const result = compareArrays(arr1, arr2);
29
+ console.log("Result:", result);
30
+ expect(result).toEqual([4, 3]); // 4 fields, 3 matches
31
+ });
32
+
33
+ it("should handle empty arrays", () => {
34
+ const arr1: any[] = [];
35
+ const arr2: any[] = [];
36
+ const result = compareArrays(arr1, arr2);
37
+ console.log("Result:", result);
38
+ expect(result).toEqual([0, 0]); // 0 fields, 0 matches
39
+ });
40
+
41
+ it("should handle arrays with different lengths", () => {
42
+ const arr1 = [1, 2, 3];
43
+ const arr2 = [1, 2];
44
+ const result = compareArrays(arr1, arr2);
45
+ console.log("Result:", result);
46
+ expect(result).toEqual([2, 2]); // 2 fields, 2 matches
47
+ });
48
+
49
+ it("should handle arrays with undefined values", () => {
50
+ const arr1 = [1, undefined, 3];
51
+ const arr2 = [1, 2, 3];
52
+ const result = compareArrays(arr1, arr2);
53
+ console.log("Result:", result);
54
+ expect(result).toEqual([3, 2]); // 3 fields, 2 matches
55
+ });
56
+
57
+ it("should handle nested empty arrays", () => {
58
+ const arr1 = [1, [], [[], []], 3];
59
+ const arr2 = [1, [2], [[], []], 3];
60
+ const result = compareArrays(arr1, arr2);
61
+ console.log("Result:", result);
62
+ expect(result).toEqual([3, 2]); // 3 fields, 2 matches
63
+ });
64
+
65
+ it("should handle arrays of objects", () => {
66
+ const arr1 = [{ a: 1 }, { b: 2 }];
67
+ const arr2 = [{ a: 1 }, { b: 3 }];
68
+ const result = compareArrays(arr1, arr2);
69
+ console.log("Result:", result);
70
+ expect(result).toEqual([2, 1]); // 2 fields, 1 matches
71
+ });
72
+
73
+ it("should throw an error for max depth exceeded", () => {
74
+ const arr1 = [1, [2, [3, [4, [5, [6]]]]]];
75
+ const arr2 = [1, [2, [3, [4, [5, [6]]]]]];
76
+ expect(() => compareArrays(arr1, arr2, 0)).toThrow("Max depth exceeded");
77
+ });
78
+ });
79
+
80
+ describe("Dataset Comparison", () => {
81
+ it("should compare two identical datasets", () => {
82
+ const result = compareDatasets(sampleData1, sampleData1);
83
+ console.log("Result:", result);
84
+ expect(result).toEqual([56, 56]); // 20 fields, 20 matches
85
+ });
86
+
87
+ it("should compare two different datasets", () => {
88
+ const result = compareDatasets(sampleData1, sampleData2);
89
+ console.log("Result:", result);
90
+ expect(result).toEqual([53, 44]); // 20 fields, 10 matches
91
+ });
92
+ });
@@ -89,9 +89,7 @@ describe('Confidence Calculation', () => {
89
89
  ram: 4096
90
90
  },
91
91
  timezone: 'Europe/London',
92
- ip: '178.238.11.6',
93
- languages: ['en-GB', 'en'],
94
- userAgent: 'Mozilla/5.0 (compatible; Konqueror/2.2.2-3; Linux)'
92
+ ip: '178.238.11.6'
95
93
  };
96
94
  const confidence = calculateConfidence(sampleData1, partialData);
97
95
  console.log('Confidence for partially similar data:', confidence);