@svrnsec/pulse 0.6.0 → 0.7.0
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/README.md +242 -82
- package/SECURITY.md +1 -1
- package/dist/pulse.cjs.js +25 -25
- package/dist/pulse.cjs.js.map +1 -1
- package/dist/pulse.esm.js +25 -25
- package/dist/pulse.esm.js.map +1 -1
- package/index.d.ts +3 -3
- package/package.json +22 -3
- package/src/analysis/audio.js +1 -1
- package/src/analysis/authenticityAudit.js +13 -10
- package/src/analysis/coherence.js +1 -1
- package/src/analysis/coordinatedBehavior.js +804 -0
- package/src/analysis/heuristic.js +1 -1
- package/src/analysis/jitter.js +1 -1
- package/src/analysis/llm.js +1 -1
- package/src/analysis/provider.js +1 -1
- package/src/analysis/refraction.js +391 -0
- package/src/collector/adaptive.js +1 -1
- package/src/collector/bio.js +1 -1
- package/src/collector/canvas.js +1 -1
- package/src/collector/dram.js +1 -1
- package/src/collector/enf.js +1 -1
- package/src/collector/entropy.js +1 -1
- package/src/collector/gpu.js +1 -1
- package/src/collector/sabTimer.js +2 -2
- package/src/fingerprint.js +2 -2
- package/src/index.js +6 -6
- package/src/integrations/react.js +2 -2
- package/src/middleware/express.js +2 -2
- package/src/middleware/next.js +3 -3
- package/src/proof/fingerprint.js +1 -1
- package/src/proof/validator.js +1 -1
- package/src/registry/serializer.js +4 -4
package/dist/pulse.esm.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createRequire } from 'module';
|
|
|
2
2
|
import { randomFillSync } from 'node:crypto';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* @
|
|
5
|
+
* @svrnsec/pulse — Statistical Jitter Analysis
|
|
6
6
|
*
|
|
7
7
|
* Analyses the timing distribution from the entropy probe to classify
|
|
8
8
|
* the host as a real consumer device or a sanitised datacenter VM.
|
|
@@ -458,7 +458,7 @@ var jitter = /*#__PURE__*/Object.freeze({
|
|
|
458
458
|
});
|
|
459
459
|
|
|
460
460
|
/**
|
|
461
|
-
* @
|
|
461
|
+
* @svrnsec/pulse — Adaptive Entropy Probe
|
|
462
462
|
*
|
|
463
463
|
* Runs the WASM probe in batches and stops early once the signal is decisive.
|
|
464
464
|
*
|
|
@@ -658,7 +658,7 @@ async function collectEntropyAdaptive(wasmModule, opts = {}) {
|
|
|
658
658
|
*/
|
|
659
659
|
|
|
660
660
|
/**
|
|
661
|
-
* @
|
|
661
|
+
* @svrnsec/pulse — Entropy Collector
|
|
662
662
|
*
|
|
663
663
|
* Bridges the Rust/WASM matrix-multiply probe into JavaScript.
|
|
664
664
|
* The WASM module is lazily initialised once and cached for subsequent calls.
|
|
@@ -853,7 +853,7 @@ function _mean$4(arr) {
|
|
|
853
853
|
*/
|
|
854
854
|
|
|
855
855
|
/**
|
|
856
|
-
* @
|
|
856
|
+
* @svrnsec/pulse — Bio-Binding Layer
|
|
857
857
|
*
|
|
858
858
|
* Captures mouse-movement micro-stutters and keystroke-cadence dynamics
|
|
859
859
|
* WHILE the hardware entropy probe is running. Computes the
|
|
@@ -1691,7 +1691,7 @@ class BLAKE3 extends BLAKE2 {
|
|
|
1691
1691
|
const blake3 = /* @__PURE__ */ createXOFer((opts) => new BLAKE3(opts));
|
|
1692
1692
|
|
|
1693
1693
|
/**
|
|
1694
|
-
* @
|
|
1694
|
+
* @svrnsec/pulse — Hardware Fingerprint & Proof Builder
|
|
1695
1695
|
*
|
|
1696
1696
|
* Assembles all collected signals into a canonical ProofPayload, then
|
|
1697
1697
|
* produces a BLAKE3 commitment: BLAKE3(canonicalJSON(payload)).
|
|
@@ -1958,7 +1958,7 @@ function _round$1(v, decimals) {
|
|
|
1958
1958
|
}
|
|
1959
1959
|
|
|
1960
1960
|
/**
|
|
1961
|
-
* @
|
|
1961
|
+
* @svrnsec/pulse — GPU Canvas Fingerprint
|
|
1962
1962
|
*
|
|
1963
1963
|
* Collects device-class signals from WebGL and 2D Canvas rendering.
|
|
1964
1964
|
* The exact pixel values of GPU-rendered scenes are vendor/driver-specific
|
|
@@ -2197,7 +2197,7 @@ function _compileShader(gl, type, source) {
|
|
|
2197
2197
|
}
|
|
2198
2198
|
|
|
2199
2199
|
/**
|
|
2200
|
-
* @
|
|
2200
|
+
* @svrnsec/pulse — AudioContext Oscillator Jitter
|
|
2201
2201
|
*
|
|
2202
2202
|
* Measures the scheduling jitter of the browser's audio pipeline.
|
|
2203
2203
|
* Real audio hardware callbacks are driven by a hardware interrupt (IRQ)
|
|
@@ -2411,7 +2411,7 @@ function _percentile(arr, p) {
|
|
|
2411
2411
|
}
|
|
2412
2412
|
|
|
2413
2413
|
/**
|
|
2414
|
-
* @
|
|
2414
|
+
* @svrnsec/pulse — WebGPU Thermal Variance Probe
|
|
2415
2415
|
*
|
|
2416
2416
|
* Runs a compute shader on the GPU and measures dispatch timing variance.
|
|
2417
2417
|
*
|
|
@@ -2657,7 +2657,7 @@ function _timeout(ms, msg) {
|
|
|
2657
2657
|
*/
|
|
2658
2658
|
|
|
2659
2659
|
/**
|
|
2660
|
-
* @
|
|
2660
|
+
* @svrnsec/pulse — DRAM Refresh Cycle Detector
|
|
2661
2661
|
*
|
|
2662
2662
|
* DDR4 DRAM refreshes every 7.8 ms (tREFI per JEDEC JESD79-4). During a
|
|
2663
2663
|
* refresh, the memory controller stalls all access requests for ~350 ns.
|
|
@@ -2861,7 +2861,7 @@ function _autocorr(data, maxLag) {
|
|
|
2861
2861
|
}
|
|
2862
2862
|
|
|
2863
2863
|
/**
|
|
2864
|
-
* @
|
|
2864
|
+
* @svrnsec/pulse — SharedArrayBuffer Microsecond Timer
|
|
2865
2865
|
*
|
|
2866
2866
|
* Bypasses browser timer clamping (Brave 100µs cap, Firefox 20µs cap, Safari
|
|
2867
2867
|
* 1ms cap) using Atomics.wait() which is exempt from clamping because it maps
|
|
@@ -2900,7 +2900,7 @@ function isSabAvailable() {
|
|
|
2900
2900
|
typeof SharedArrayBuffer !== 'undefined' &&
|
|
2901
2901
|
typeof Atomics !== 'undefined' &&
|
|
2902
2902
|
typeof Atomics.wait === 'function' &&
|
|
2903
|
-
crossOriginIsolated
|
|
2903
|
+
typeof crossOriginIsolated !== 'undefined' && crossOriginIsolated === true // COOP+COEP headers
|
|
2904
2904
|
);
|
|
2905
2905
|
}
|
|
2906
2906
|
|
|
@@ -3053,7 +3053,7 @@ function _getAtomicsTs() {
|
|
|
3053
3053
|
}
|
|
3054
3054
|
|
|
3055
3055
|
/**
|
|
3056
|
-
* @
|
|
3056
|
+
* @svrnsec/pulse — Electrical Network Frequency (ENF) Detection
|
|
3057
3057
|
*
|
|
3058
3058
|
* ┌─────────────────────────────────────────────────────────────────────────┐
|
|
3059
3059
|
* │ WHAT THIS IS │
|
|
@@ -3364,7 +3364,7 @@ function _noEnf(reason) {
|
|
|
3364
3364
|
*/
|
|
3365
3365
|
|
|
3366
3366
|
/**
|
|
3367
|
-
* @
|
|
3367
|
+
* @svrnsec/pulse — LLM / AI Agent Behavioral Fingerprint
|
|
3368
3368
|
*
|
|
3369
3369
|
* Detects automation driven by large language models, headless browsers
|
|
3370
3370
|
* controlled by AI agents (AutoGPT, CrewAI, browser-use, Playwright+LLM,
|
|
@@ -3992,7 +3992,7 @@ function _stripAnsi(s) {
|
|
|
3992
3992
|
}
|
|
3993
3993
|
|
|
3994
3994
|
/**
|
|
3995
|
-
* @
|
|
3995
|
+
* @svrnsec/pulse — Cross-Metric Heuristic Engine
|
|
3996
3996
|
*
|
|
3997
3997
|
* Instead of checking individual thresholds in isolation, this module looks
|
|
3998
3998
|
* at the *relationships* between metrics. A sophisticated adversary can spoof
|
|
@@ -4420,7 +4420,7 @@ function _empty$1() {
|
|
|
4420
4420
|
}
|
|
4421
4421
|
|
|
4422
4422
|
/**
|
|
4423
|
-
* @
|
|
4423
|
+
* @svrnsec/pulse — Zero-Latency Second-Stage Coherence Analysis
|
|
4424
4424
|
*
|
|
4425
4425
|
* Runs entirely on data already collected by the entropy probe, bio
|
|
4426
4426
|
* collector, canvas fingerprinter, and audio analyser.
|
|
@@ -4923,7 +4923,7 @@ function _empty(threshold) {
|
|
|
4923
4923
|
*/
|
|
4924
4924
|
|
|
4925
4925
|
/**
|
|
4926
|
-
* @
|
|
4926
|
+
* @svrnsec/pulse — Hypervisor & Cloud Provider Fingerprinter
|
|
4927
4927
|
*
|
|
4928
4928
|
* Each hypervisor has a distinct "steal-time rhythm" — a characteristic
|
|
4929
4929
|
* pattern in how it schedules guest vCPUs on host physical cores.
|
|
@@ -5172,7 +5172,7 @@ function _estimateQuantum({ lag1, lag25, lag50, qe }) {
|
|
|
5172
5172
|
}
|
|
5173
5173
|
|
|
5174
5174
|
/**
|
|
5175
|
-
* @
|
|
5175
|
+
* @svrnsec/pulse — High-Level Fingerprint Class
|
|
5176
5176
|
*
|
|
5177
5177
|
* The developer-facing API. Instead of forcing devs to understand Hurst
|
|
5178
5178
|
* Exponents and Quantization Entropy, they get a Fingerprint object with
|
|
@@ -5180,7 +5180,7 @@ function _estimateQuantum({ lag1, lag25, lag50, qe }) {
|
|
|
5180
5180
|
*
|
|
5181
5181
|
* Usage:
|
|
5182
5182
|
*
|
|
5183
|
-
* import { Fingerprint } from '@
|
|
5183
|
+
* import { Fingerprint } from '@svrnsec/pulse';
|
|
5184
5184
|
*
|
|
5185
5185
|
* const fp = await Fingerprint.collect({ nonce });
|
|
5186
5186
|
*
|
|
@@ -5639,7 +5639,7 @@ function _round(v, d) {
|
|
|
5639
5639
|
}
|
|
5640
5640
|
|
|
5641
5641
|
/**
|
|
5642
|
-
* @
|
|
5642
|
+
* @svrnsec/pulse — Server-Side Validator
|
|
5643
5643
|
*
|
|
5644
5644
|
* Verifies a ProofPayload + BLAKE3 commitment received from the client.
|
|
5645
5645
|
* This module is for NODE.JS / SERVER use only. It should NOT be bundled
|
|
@@ -6353,14 +6353,14 @@ function renderInlineUpdateHint(latest) {
|
|
|
6353
6353
|
}
|
|
6354
6354
|
|
|
6355
6355
|
/**
|
|
6356
|
-
* @
|
|
6356
|
+
* @svrnsec/pulse
|
|
6357
6357
|
*
|
|
6358
6358
|
* Physical Turing Test — distinguishes a real consumer device with a human
|
|
6359
6359
|
* operator from a sanitised Datacenter VM / AI Instance.
|
|
6360
6360
|
*
|
|
6361
6361
|
* Usage (client-side):
|
|
6362
6362
|
*
|
|
6363
|
-
* import { pulse } from '@
|
|
6363
|
+
* import { pulse } from '@svrnsec/pulse';
|
|
6364
6364
|
*
|
|
6365
6365
|
* // 1. Get a server-issued nonce (prevents replay attacks)
|
|
6366
6366
|
* const { nonce } = await fetch('/api/pulse-challenge').then(r => r.json());
|
|
@@ -6376,7 +6376,7 @@ function renderInlineUpdateHint(latest) {
|
|
|
6376
6376
|
*
|
|
6377
6377
|
* Usage (server-side):
|
|
6378
6378
|
*
|
|
6379
|
-
* import { validateProof, generateNonce } from '@
|
|
6379
|
+
* import { validateProof, generateNonce } from '@svrnsec/pulse/validator';
|
|
6380
6380
|
*
|
|
6381
6381
|
* // Challenge endpoint
|
|
6382
6382
|
* app.get('/api/pulse-challenge', (req, res) => {
|
|
@@ -6473,7 +6473,7 @@ async function _pulseHosted(opts) {
|
|
|
6473
6473
|
// ---------------------------------------------------------------------------
|
|
6474
6474
|
|
|
6475
6475
|
/**
|
|
6476
|
-
* Run the full @
|
|
6476
|
+
* Run the full @svrnsec/pulse probe and return a signed commitment.
|
|
6477
6477
|
*
|
|
6478
6478
|
* Two modes:
|
|
6479
6479
|
* - pulse({ nonce }) — self-hosted (you manage the nonce server)
|
|
@@ -6492,7 +6492,7 @@ async function pulse(opts = {}) {
|
|
|
6492
6492
|
const { nonce } = opts;
|
|
6493
6493
|
if (!nonce || typeof nonce !== 'string') {
|
|
6494
6494
|
throw new Error(
|
|
6495
|
-
'@
|
|
6495
|
+
'@svrnsec/pulse: opts.nonce is required (self-hosted), or pass opts.apiKey for zero-config hosted mode.'
|
|
6496
6496
|
);
|
|
6497
6497
|
}
|
|
6498
6498
|
|
|
@@ -6571,7 +6571,7 @@ async function _runProbe(opts) {
|
|
|
6571
6571
|
const [enfResult, gpuResult, dramResult, llmResult] = await Promise.all([
|
|
6572
6572
|
collectEnfTimings().catch(() => null),
|
|
6573
6573
|
collectGpuEntropy().catch(() => null),
|
|
6574
|
-
collectDramTimings().catch(() => null),
|
|
6574
|
+
Promise.resolve(collectDramTimings()).catch(() => null),
|
|
6575
6575
|
Promise.resolve(detectLlmAgent(bioSnapshot)).catch(() => null),
|
|
6576
6576
|
]);
|
|
6577
6577
|
|