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