@npm-pipl/device-intelligence 1.1.1 → 1.1.3
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/dist/device-intelligence.cjs.js +144 -50
- package/dist/device-intelligence.cjs.js.map +1 -1
- package/dist/device-intelligence.esm.js +144 -50
- package/dist/device-intelligence.esm.js.map +1 -1
- package/dist/device-intelligence.esm.min.js +2 -2
- package/dist/device-intelligence.esm.min.js.map +1 -1
- package/dist/device-intelligence.js +144 -50
- package/dist/device-intelligence.js.map +1 -1
- package/dist/device-intelligence.min.js +2 -2
- package/dist/device-intelligence.min.js.map +1 -1
- package/dist/device-intelligence.umd.js +144 -50
- package/dist/device-intelligence.umd.js.map +1 -1
- package/dist/device-intelligence.umd.min.js +2 -2
- package/dist/device-intelligence.umd.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Device Intelligence SDK v1.1.
|
|
2
|
+
* Device Intelligence SDK v1.1.3
|
|
3
3
|
* (c) 2026 Your Company
|
|
4
4
|
* Released under the MIT License
|
|
5
5
|
*/
|
|
@@ -5519,7 +5519,19 @@ const automationDetected = {
|
|
|
5519
5519
|
// Check webdriver property
|
|
5520
5520
|
if (nav.webdriver === true)
|
|
5521
5521
|
return true;
|
|
5522
|
-
//
|
|
5522
|
+
// Detect navigator.webdriver tampering (stealth plugins redefine the getter)
|
|
5523
|
+
try {
|
|
5524
|
+
const desc = Object.getOwnPropertyDescriptor(Navigator.prototype, "webdriver");
|
|
5525
|
+
if (desc?.get) {
|
|
5526
|
+
const src = Function.prototype.toString.call(desc.get);
|
|
5527
|
+
if (!/\[native code\]/.test(src))
|
|
5528
|
+
return true;
|
|
5529
|
+
}
|
|
5530
|
+
}
|
|
5531
|
+
catch {
|
|
5532
|
+
/* ignore */
|
|
5533
|
+
}
|
|
5534
|
+
// Check for automation-related properties on window / document
|
|
5523
5535
|
const automationProps = [
|
|
5524
5536
|
"__selenium_unwrapped",
|
|
5525
5537
|
"__webdriver_evaluate",
|
|
@@ -5538,12 +5550,22 @@ const automationDetected = {
|
|
|
5538
5550
|
"$chrome_asyncScriptInfo",
|
|
5539
5551
|
"__nightmare",
|
|
5540
5552
|
"__puppeteer_evaluation_script__",
|
|
5541
|
-
"__playwright_evaluation_script__"
|
|
5553
|
+
"__playwright_evaluation_script__",
|
|
5554
|
+
"__playwright",
|
|
5555
|
+
"__pw_manual"
|
|
5542
5556
|
];
|
|
5543
5557
|
for (const prop of automationProps) {
|
|
5544
5558
|
if (prop in win || prop in document)
|
|
5545
5559
|
return true;
|
|
5546
5560
|
}
|
|
5561
|
+
// Dynamic $cdc_ scan — ChromeDriver injects keys with varying suffixes
|
|
5562
|
+
try {
|
|
5563
|
+
if (Object.keys(win).some((k) => k.startsWith("$cdc_")))
|
|
5564
|
+
return true;
|
|
5565
|
+
}
|
|
5566
|
+
catch {
|
|
5567
|
+
/* ignore */
|
|
5568
|
+
}
|
|
5547
5569
|
// Check for PhantomJS
|
|
5548
5570
|
if ("callPhantom" in win || "_phantom" in win || "phantom" in win) {
|
|
5549
5571
|
return true;
|
|
@@ -5553,8 +5575,44 @@ const automationDetected = {
|
|
|
5553
5575
|
if (ua.includes("headless") || ua.includes("phantomjs")) {
|
|
5554
5576
|
return true;
|
|
5555
5577
|
}
|
|
5556
|
-
//
|
|
5557
|
-
|
|
5578
|
+
// WebGL renderer — headless Chromium uses SwiftShader (software renderer)
|
|
5579
|
+
try {
|
|
5580
|
+
const canvas = document.createElement("canvas");
|
|
5581
|
+
const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
|
5582
|
+
if (gl) {
|
|
5583
|
+
const dbg = gl.getExtension("WEBGL_debug_renderer_info");
|
|
5584
|
+
if (dbg) {
|
|
5585
|
+
const renderer = gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL);
|
|
5586
|
+
if (typeof renderer === "string" && /swiftshader/i.test(renderer)) {
|
|
5587
|
+
return true;
|
|
5588
|
+
}
|
|
5589
|
+
}
|
|
5590
|
+
}
|
|
5591
|
+
}
|
|
5592
|
+
catch {
|
|
5593
|
+
/* ignore */
|
|
5594
|
+
}
|
|
5595
|
+
// Plugins — headless browsers report 0 plugins; real Chrome always has >=1
|
|
5596
|
+
try {
|
|
5597
|
+
if (nav.plugins && nav.plugins.length === 0 && !ua.includes("firefox")) {
|
|
5598
|
+
return true;
|
|
5599
|
+
}
|
|
5600
|
+
}
|
|
5601
|
+
catch {
|
|
5602
|
+
/* ignore */
|
|
5603
|
+
}
|
|
5604
|
+
// Chrome object inconsistency — Chrome UA but missing window.chrome
|
|
5605
|
+
try {
|
|
5606
|
+
if (ua.includes("chrome") && !("chrome" in win)) {
|
|
5607
|
+
return true;
|
|
5608
|
+
}
|
|
5609
|
+
if (win.chrome && !win.chrome.runtime && !win.chrome.csi) {
|
|
5610
|
+
return true;
|
|
5611
|
+
}
|
|
5612
|
+
}
|
|
5613
|
+
catch {
|
|
5614
|
+
/* ignore */
|
|
5615
|
+
}
|
|
5558
5616
|
return false;
|
|
5559
5617
|
}
|
|
5560
5618
|
};
|
|
@@ -5716,67 +5774,103 @@ const debuggerDetected = {
|
|
|
5716
5774
|
const incognitoMode = {
|
|
5717
5775
|
category: "risk",
|
|
5718
5776
|
key: "incognito_mode",
|
|
5719
|
-
version:
|
|
5777
|
+
version: 2,
|
|
5720
5778
|
cacheTtlMs: 300000,
|
|
5721
|
-
timeoutMs:
|
|
5779
|
+
timeoutMs: 3000,
|
|
5722
5780
|
collect: async () => {
|
|
5723
|
-
|
|
5781
|
+
const ua = (navigator.userAgent || "").toLowerCase();
|
|
5782
|
+
const isChromium = ua.includes("chrome") || ua.includes("chromium");
|
|
5783
|
+
const isFirefox = ua.includes("firefox");
|
|
5784
|
+
// ── Storage quota ──────────────────────────────────────────────────
|
|
5785
|
+
// Normal mode: quota ≈ 50–60 % of disk (tens to hundreds of GB).
|
|
5786
|
+
// Incognito: quota is RAM-based and much smaller.
|
|
5787
|
+
// • Safari / Firefox private: typically < 200 MB
|
|
5788
|
+
// • Chrome incognito: scales with device RAM (1–16 GB)
|
|
5724
5789
|
try {
|
|
5725
|
-
const
|
|
5726
|
-
if (
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5790
|
+
const est = await withTimeout(navigator.storage.estimate(), 1500);
|
|
5791
|
+
if (est && est.quota !== undefined) {
|
|
5792
|
+
const quota = est.quota;
|
|
5793
|
+
// Tier 1: very small quota — catches Safari & Firefox private
|
|
5794
|
+
if (quota < 200000000) {
|
|
5795
|
+
return {
|
|
5796
|
+
is_private: true,
|
|
5797
|
+
confidence: "high",
|
|
5798
|
+
method: "storage_quota"
|
|
5799
|
+
};
|
|
5800
|
+
}
|
|
5801
|
+
if (isChromium) {
|
|
5802
|
+
// Tier 2: compare quota to device memory (most reliable for Chrome).
|
|
5803
|
+
// In incognito, quota is RAM-based → quota ≤ ~RAM.
|
|
5804
|
+
// In normal mode, quota is disk-based → quota >> RAM.
|
|
5805
|
+
// navigator.deviceMemory is capped at 8 (GB) and coarsened,
|
|
5806
|
+
// so we use a 3× multiplier to cover the gap between the
|
|
5807
|
+
// capped value and real RAM. Even on a 64 GB RAM machine
|
|
5808
|
+
// (deviceMemory=8), incognito quota (~16 GB) < 3×8 GB = 24 GB,
|
|
5809
|
+
// while normal quota on a 128 GB SSD (~64 GB) > 24 GB.
|
|
5810
|
+
const deviceMemGB = navigator.deviceMemory;
|
|
5811
|
+
if (deviceMemGB && quota < deviceMemGB * 3 * 1024 * 1024 * 1024) {
|
|
5812
|
+
return {
|
|
5813
|
+
is_private: true,
|
|
5814
|
+
confidence: "medium",
|
|
5815
|
+
method: "storage_quota_vs_memory"
|
|
5816
|
+
};
|
|
5817
|
+
}
|
|
5818
|
+
// Tier 3: absolute fallback when deviceMemory is unavailable.
|
|
5819
|
+
// 16 GB catches incognito on most machines (up to ~32 GB RAM)
|
|
5820
|
+
// while staying below normal-mode quota on any disk ≥ 64 GB.
|
|
5821
|
+
if (!deviceMemGB && quota < 16000000000) {
|
|
5822
|
+
return {
|
|
5823
|
+
is_private: true,
|
|
5824
|
+
confidence: "medium",
|
|
5825
|
+
method: "storage_quota_chrome"
|
|
5826
|
+
};
|
|
5827
|
+
}
|
|
5828
|
+
}
|
|
5734
5829
|
}
|
|
5735
5830
|
}
|
|
5736
5831
|
catch {
|
|
5737
|
-
//
|
|
5832
|
+
// API not supported
|
|
5738
5833
|
}
|
|
5739
|
-
//
|
|
5834
|
+
// ── webkitTemporaryStorage (Chromium legacy) ───────────────────────
|
|
5835
|
+
// Still present in some Chromium builds; incognito returns a small
|
|
5836
|
+
// quota (often ≈ 120 MB) vs normal (multiple GB).
|
|
5740
5837
|
try {
|
|
5741
|
-
const
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5838
|
+
const tmpStorage = navigator.webkitTemporaryStorage;
|
|
5839
|
+
if (tmpStorage?.queryUsageAndQuota) {
|
|
5840
|
+
const quota = await withTimeout(new Promise((resolve, reject) => {
|
|
5841
|
+
tmpStorage.queryUsageAndQuota((_usage, q) => resolve(q), () => reject(new Error("quota query failed")));
|
|
5842
|
+
}), 1000);
|
|
5843
|
+
if (quota !== null && quota < 200000000) {
|
|
5844
|
+
return {
|
|
5845
|
+
is_private: true,
|
|
5846
|
+
confidence: "medium",
|
|
5847
|
+
method: "webkit_temporary_storage"
|
|
5848
|
+
};
|
|
5849
|
+
}
|
|
5752
5850
|
}
|
|
5753
5851
|
}
|
|
5754
5852
|
catch {
|
|
5755
|
-
|
|
5756
|
-
is_private: true,
|
|
5757
|
-
confidence: "medium",
|
|
5758
|
-
method: "indexeddb"
|
|
5759
|
-
};
|
|
5853
|
+
// Not available
|
|
5760
5854
|
}
|
|
5761
|
-
//
|
|
5855
|
+
// ── IndexedDB ────────────────────────────────────────────────────────
|
|
5856
|
+
// Firefox private mode rejects indexedDB.open(). Some Chrome/Edge
|
|
5857
|
+
// incognito edge-cases (enterprise policies, older builds) also fail
|
|
5858
|
+
// here, so we keep this as a universal late fallback.
|
|
5762
5859
|
try {
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
// Timeout - can't determine
|
|
5772
|
-
}
|
|
5773
|
-
}
|
|
5860
|
+
await withTimeout(new Promise((resolve, reject) => {
|
|
5861
|
+
const req = indexedDB.open("_di_priv_check");
|
|
5862
|
+
req.onerror = () => reject(new Error("blocked"));
|
|
5863
|
+
req.onsuccess = () => {
|
|
5864
|
+
req.result.close();
|
|
5865
|
+
resolve(true);
|
|
5866
|
+
};
|
|
5867
|
+
}), 1000);
|
|
5774
5868
|
}
|
|
5775
5869
|
catch {
|
|
5776
5870
|
return {
|
|
5777
5871
|
is_private: true,
|
|
5778
|
-
confidence: "medium",
|
|
5779
|
-
method: "
|
|
5872
|
+
confidence: isFirefox ? "medium" : "low",
|
|
5873
|
+
method: "indexeddb"
|
|
5780
5874
|
};
|
|
5781
5875
|
}
|
|
5782
5876
|
return {
|
|
@@ -5930,7 +6024,7 @@ function getDefaultCollectors() {
|
|
|
5930
6024
|
return getAllCollectors();
|
|
5931
6025
|
}
|
|
5932
6026
|
|
|
5933
|
-
var version = "1.1.
|
|
6027
|
+
var version = "1.1.3";
|
|
5934
6028
|
var packageJson = {
|
|
5935
6029
|
version: version};
|
|
5936
6030
|
|