@prosopo/fingerprint 2.7.64 → 2.8.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/.turbo/turbo-build$colon$cjs.log +7 -6
- package/.turbo/turbo-build$colon$tsc.log +9 -9
- package/.turbo/turbo-build.log +6 -5
- package/CHANGELOG.md +73 -0
- package/dist/cjs/index.cjs +17 -1
- package/dist/cjs/proof.cjs +2 -1
- package/dist/cjs/summary.cjs +73 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +25 -0
- package/dist/index.test.js.map +1 -0
- package/dist/proof.d.ts.map +1 -1
- package/dist/proof.js +2 -1
- package/dist/proof.js.map +1 -1
- package/dist/summary.d.ts +5 -0
- package/dist/summary.d.ts.map +1 -0
- package/dist/summary.js +73 -0
- package/dist/summary.js.map +1 -0
- package/dist/summary.test.d.ts +2 -0
- package/dist/summary.test.d.ts.map +1 -0
- package/dist/summary.test.js +143 -0
- package/dist/summary.test.js.map +1 -0
- package/package.json +13 -8
|
@@ -19,14 +19,15 @@ ViteCommonJSConfig: .
|
|
|
19
19
|
]
|
|
20
20
|
}
|
|
21
21
|
[33mThe plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the [1mresolve.tsconfigPaths[22m option. You can remove the plugin and set [1mresolve.tsconfigPaths: true[22m in your Vite config instead.[39m
|
|
22
|
-
[36mvite v8.1.
|
|
22
|
+
[36mvite v8.1.6 [32mbuilding ssr environment for production...[36m[39m
|
|
23
23
|
Bundle build started
|
|
24
24
|
[2K
|
|
25
|
-
✓
|
|
25
|
+
✓ 5 modules transformed.
|
|
26
26
|
rendering chunks...
|
|
27
27
|
computing gzip size...
|
|
28
|
-
dist/cjs/
|
|
29
|
-
dist/cjs/
|
|
30
|
-
dist/cjs/
|
|
28
|
+
dist/cjs/merkle.cjs 2.84 kB │ gzip: 1.09 kB
|
|
29
|
+
dist/cjs/summary.cjs 2.95 kB │ gzip: 1.28 kB
|
|
30
|
+
dist/cjs/index.cjs 3.40 kB │ gzip: 1.25 kB
|
|
31
|
+
dist/cjs/proof.cjs 4.32 kB │ gzip: 1.71 kB
|
|
31
32
|
|
|
32
|
-
[32m✓ built in
|
|
33
|
+
[32m✓ built in 51ms[39m
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
$ tsc --build --verbose
|
|
2
|
-
|
|
2
|
+
5:07:53 PM - Projects in this build:
|
|
3
3
|
* ../../dev/config/tsconfig.json
|
|
4
4
|
* ../fingerprintjs/tsconfig.json
|
|
5
5
|
* ../util/tsconfig.json
|
|
@@ -8,19 +8,19 @@ $ tsc --build --verbose
|
|
|
8
8
|
* ../types/tsconfig.json
|
|
9
9
|
* tsconfig.json
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
5:07:53 PM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
5:07:53 PM - Project '../fingerprintjs/tsconfig.json' is up to date because newest input '../fingerprintjs/src/utils/browser.ts' is older than output '../fingerprintjs/tsconfig.tsbuildinfo'
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
5:07:53 PM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
5:07:53 PM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
5:07:53 PM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
5:07:53 PM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/types.test-d.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
5:07:53 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
5:07:53 PM - Building project '/home/runner/work/captcha/captcha/packages/fingerprint/tsconfig.json'...
|
|
26
26
|
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -20,15 +20,16 @@ ViteEsmConfig: .
|
|
|
20
20
|
]
|
|
21
21
|
}
|
|
22
22
|
[33mThe plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the [1mresolve.tsconfigPaths[22m option. You can remove the plugin and set [1mresolve.tsconfigPaths: true[22m in your Vite config instead.[39m
|
|
23
|
-
[36mvite v8.1.
|
|
23
|
+
[36mvite v8.1.6 [32mbuilding ssr environment for production...[36m[39m
|
|
24
24
|
Bundle build started
|
|
25
25
|
[2K
|
|
26
|
-
✓
|
|
26
|
+
✓ 5 modules transformed.
|
|
27
27
|
rendering chunks...
|
|
28
28
|
computing gzip size...
|
|
29
29
|
dist/_virtual/_rolldown/runtime.js 0.04 kB │ gzip: 0.06 kB
|
|
30
|
-
dist/index.js 2.06 kB │ gzip: 0.81 kB
|
|
31
30
|
dist/merkle.js 2.68 kB │ gzip: 1.06 kB
|
|
32
|
-
dist/
|
|
31
|
+
dist/summary.js 2.89 kB │ gzip: 1.26 kB
|
|
32
|
+
dist/index.js 2.89 kB │ gzip: 1.17 kB
|
|
33
|
+
dist/proof.js 4.05 kB │ gzip: 1.67 kB
|
|
33
34
|
|
|
34
|
-
[32m✓ built in
|
|
35
|
+
[32m✓ built in 47ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,78 @@
|
|
|
1
1
|
# @prosopo/fingerprint
|
|
2
2
|
|
|
3
|
+
## 2.8.0
|
|
4
|
+
### Minor Changes
|
|
5
|
+
|
|
6
|
+
- 2bcf2fe: Store a compact summary of each verified proof of fingerprint on the PoW record,
|
|
7
|
+
and add a device grouping value to the proof.
|
|
8
|
+
|
|
9
|
+
Until now the proof was checked and discarded, so nothing it disclosed survived
|
|
10
|
+
the request. `summariseFingerprintProof` reduces a proof to its commitment root,
|
|
11
|
+
the values it disclosed, and a hash over the subset of those values listed in
|
|
12
|
+
`GROUP_KEYS`, and the provider writes that onto the captcha record.
|
|
13
|
+
|
|
14
|
+
The proof now also discloses `deviceBucket`, a new component from
|
|
15
|
+
`@prosopo/fingerprintjs`. It is a 128 bit hash of the device traits that stay the
|
|
16
|
+
same between sessions: platform, screen resolution, colour depth, core count and
|
|
17
|
+
installed fonts. Disclosing it lets us tell that two visits came from the same
|
|
18
|
+
kind of device without being told the platform, the screen size or the font list,
|
|
19
|
+
which disclosing those values individually would have done. It is stored as
|
|
20
|
+
`bucketId`.
|
|
21
|
+
|
|
22
|
+
`deviceBucket` is excluded from the visitorId. The account address is a pure
|
|
23
|
+
function of the visitorId, so folding a new component in would rotate every
|
|
24
|
+
account on record and orphan its sighting history. `forIdentity` drops it before
|
|
25
|
+
hashing, and there is a test asserting the visitorId does not move.
|
|
26
|
+
|
|
27
|
+
The summary reaches the decision machines as well as the database. It is
|
|
28
|
+
computed once, at the provider boundary, and handed to both, so the machine and
|
|
29
|
+
the stored record cannot disagree about what a proof disclosed, and a 7.8KB
|
|
30
|
+
proof is parsed and Merkle-checked once per submission instead of twice. Rules
|
|
31
|
+
read it as `input.raw.fingerprintSummary`.
|
|
32
|
+
|
|
33
|
+
There is also a new counter dimension, `deviceBucket`. One bucket on its own
|
|
34
|
+
says nothing, so counting is the whole point: a rule can now ask how much
|
|
35
|
+
traffic a kind of device has produced in a window, which no per-request field
|
|
36
|
+
can answer. The solve hook writes the counter whenever a proof disclosed a
|
|
37
|
+
bucket, and a rule naming the dimension on a request that disclosed none is
|
|
38
|
+
skipped rather than read as zero, so an `lte` clause does not match every
|
|
39
|
+
client that proved nothing.
|
|
40
|
+
|
|
41
|
+
The proof itself is still not stored. Each disclosure carries a full Merkle path,
|
|
42
|
+
which is large and spent once verified: at current traffic, retaining proofs
|
|
43
|
+
would add roughly 70GB over the collection's one-month TTL against under 3GB for
|
|
44
|
+
the summary.
|
|
45
|
+
|
|
46
|
+
A summary is only produced for a proof that passes structural verification, so
|
|
47
|
+
every stored value is one that hashes to the committed root. Bounding what those
|
|
48
|
+
values may be is separate and unchanged.
|
|
49
|
+
|
|
50
|
+
`@prosopo/fingerprint` gains a `./summary` entry point so server-side callers can
|
|
51
|
+
import this without the browser-only fingerprinting sources. The new field is
|
|
52
|
+
declared on the Mongoose schema: `strict: true` silently drops undeclared paths,
|
|
53
|
+
so omitting it would mean writing the field and never storing it.
|
|
54
|
+
|
|
55
|
+
### Patch Changes
|
|
56
|
+
|
|
57
|
+
- 46b97b7: Roll up the open Dependabot updates: express 5 (with `@types/express` 5), dotenv 18, undici 8, geolib 4, vitest 5, vite 8.1.6 everywhere, 17 minor and patch bumps (Babel, mongoose, i18next, ip-address, turbo and others), `@angular/router` in the Angular demo, and a GitHub Actions bump.
|
|
58
|
+
|
|
59
|
+
The whole vitest family moves to 5.0.4, including `@vitest/coverage-v8`, because `@vitest/browser-playwright` 5 only works with vitest 5. The `@types/express-serve-static-core` override moves to 5.1.3 to match `@types/express` 5.
|
|
60
|
+
|
|
61
|
+
`@prosopo/dotenv` now loads env files with `quiet: true`. Since dotenv 17, every load prints an "injected env" line to stderr unless told not to.
|
|
62
|
+
- Updated dependencies [46b97b7]
|
|
63
|
+
- Updated dependencies [d2148c8]
|
|
64
|
+
- Updated dependencies [2bcf2fe]
|
|
65
|
+
- @prosopo/types@5.17.0
|
|
66
|
+
- @prosopo/util-crypto@13.6.1
|
|
67
|
+
- @prosopo/fingerprintjs@5.2.0
|
|
68
|
+
|
|
69
|
+
## 2.7.65
|
|
70
|
+
### Patch Changes
|
|
71
|
+
|
|
72
|
+
- @prosopo/types@5.16.3
|
|
73
|
+
- @prosopo/fingerprintjs@5.2.0
|
|
74
|
+
- @prosopo/util-crypto@13.6.0
|
|
75
|
+
|
|
3
76
|
## 2.7.64
|
|
4
77
|
### Patch Changes
|
|
5
78
|
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_merkle = require("./merkle.cjs");
|
|
3
3
|
const require_proof = require("./proof.cjs");
|
|
4
|
+
const require_summary = require("./summary.cjs");
|
|
4
5
|
//#region src/index.ts
|
|
5
6
|
var EXCLUDED_SOURCES = ["webGlExtensions"];
|
|
6
7
|
var FingerprintJSImport = async () => import("@prosopo/fingerprintjs");
|
|
@@ -19,9 +20,22 @@ var loadComponents = () => {
|
|
|
19
20
|
}
|
|
20
21
|
return componentsCache;
|
|
21
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* Components the visitorId must not be derived from.
|
|
25
|
+
*
|
|
26
|
+
* `deviceBucket` digests components the run already produces, so folding it
|
|
27
|
+
* into the visitorId would add no entropy while changing every existing
|
|
28
|
+
* visitorId. The account address is a pure function of the visitorId, so every
|
|
29
|
+
* account on record would rotate and its sighting history would be orphaned.
|
|
30
|
+
* The proof still commits to it, and it is disclosed, which is the point of
|
|
31
|
+
* collecting it.
|
|
32
|
+
*/
|
|
33
|
+
var NON_IDENTITY_SOURCES = ["deviceBucket"];
|
|
34
|
+
/** Exported so the stability of the visitorId can be asserted directly. */
|
|
35
|
+
var forIdentity = (components) => Object.fromEntries(Object.entries(components).filter(([key]) => !NON_IDENTITY_SOURCES.includes(key)));
|
|
22
36
|
var getFingerprint = async () => {
|
|
23
37
|
const [{ hashComponents }, components] = await Promise.all([FingerprintJSImport(), loadComponents()]);
|
|
24
|
-
return hashComponents(components);
|
|
38
|
+
return hashComponents(forIdentity(components));
|
|
25
39
|
};
|
|
26
40
|
/**
|
|
27
41
|
* Produce a proof of fingerprint: a Merkle commitment to the full component set
|
|
@@ -43,6 +57,7 @@ exports.FINGERPRINT_PROOF_VERSION = require_proof.FINGERPRINT_PROOF_VERSION;
|
|
|
43
57
|
exports.buildFingerprintProofFromComponents = require_proof.buildFingerprintProofFromComponents;
|
|
44
58
|
exports.buildMerkleLayers = require_merkle.buildMerkleLayers;
|
|
45
59
|
exports.encodeFingerprintProof = require_proof.encodeFingerprintProof;
|
|
60
|
+
exports.forIdentity = forIdentity;
|
|
46
61
|
exports.getFingerprint = getFingerprint;
|
|
47
62
|
exports.getFingerprintProof = getFingerprintProof;
|
|
48
63
|
exports.hashMerklePair = require_merkle.hashMerklePair;
|
|
@@ -50,5 +65,6 @@ exports.leafHashForContent = require_proof.leafHashForContent;
|
|
|
50
65
|
exports.merkleProofFromLayers = require_merkle.merkleProofFromLayers;
|
|
51
66
|
exports.merkleRootFromLayers = require_merkle.merkleRootFromLayers;
|
|
52
67
|
exports.prefetchFingerprint = prefetchFingerprint;
|
|
68
|
+
exports.summariseFingerprintProof = require_summary.summariseFingerprintProof;
|
|
53
69
|
exports.verifyFingerprintProofStructure = require_proof.verifyFingerprintProofStructure;
|
|
54
70
|
exports.verifyMerkleProof = require_merkle.verifyMerkleProof;
|
package/dist/cjs/proof.cjs
CHANGED
|
@@ -21,7 +21,8 @@ var FINGERPRINT_DISCLOSURE_KEYS = [
|
|
|
21
21
|
"timezone",
|
|
22
22
|
"hardwareConcurrency",
|
|
23
23
|
"languages",
|
|
24
|
-
"architecture"
|
|
24
|
+
"architecture",
|
|
25
|
+
"deviceBucket"
|
|
25
26
|
];
|
|
26
27
|
var escapeKey = (key) => key.replace(/([:|\\])/g, "\\$1");
|
|
27
28
|
var componentLeafContent = (key, component) => {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const require_proof = require("./proof.cjs");
|
|
2
|
+
let _prosopo_util_crypto = require("@prosopo/util-crypto");
|
|
3
|
+
//#region src/summary.ts
|
|
4
|
+
/**
|
|
5
|
+
* The disclosed keys that are fixed by the installation and the host. A hash
|
|
6
|
+
* over them names a cohort of devices.
|
|
7
|
+
*
|
|
8
|
+
* `colorDepth` and `hardwareConcurrency` are disclosed too but kept out of the
|
|
9
|
+
* hash and stored beside it, so that the values can be read per cohort rather
|
|
10
|
+
* than only folded into it.
|
|
11
|
+
*/
|
|
12
|
+
var GROUP_KEYS = [
|
|
13
|
+
"cookiesEnabled",
|
|
14
|
+
"sessionStorage",
|
|
15
|
+
"localStorage",
|
|
16
|
+
"timezone",
|
|
17
|
+
"languages",
|
|
18
|
+
"architecture"
|
|
19
|
+
];
|
|
20
|
+
var asNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
21
|
+
/**
|
|
22
|
+
* Reduce an encoded proof to the fields worth storing, or `undefined` when it
|
|
23
|
+
* is absent, unparseable, or fails structural verification.
|
|
24
|
+
*
|
|
25
|
+
* Structural verification is not optional here: an unverified disclosure is a
|
|
26
|
+
* client-asserted value with a decorative Merkle path beside it, and storing
|
|
27
|
+
* one would put a forgeable field into an aggregation that reads as
|
|
28
|
+
* tamper-evident. Whether the values are *plausible* is a separate concern and
|
|
29
|
+
* stays in the routing machine's validator; this only refuses what does not
|
|
30
|
+
* hash together.
|
|
31
|
+
*/
|
|
32
|
+
var summariseFingerprintProof = (encoded) => {
|
|
33
|
+
if (!encoded) return void 0;
|
|
34
|
+
let proof;
|
|
35
|
+
try {
|
|
36
|
+
proof = JSON.parse(encoded);
|
|
37
|
+
} catch {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (typeof proof !== "object" || proof === null || typeof proof.root !== "string" || !Array.isArray(proof.disclosures)) return;
|
|
41
|
+
if (!require_proof.verifyFingerprintProofStructure(proof)) return void 0;
|
|
42
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
43
|
+
for (const disclosure of proof.disclosures) if (!disclosure.error) byKey.set(disclosure.key, disclosure.value);
|
|
44
|
+
const groupInput = GROUP_KEYS.map((key) => `${key}:${JSON.stringify(byKey.get(key) ?? null)}`).join("|");
|
|
45
|
+
const disclosed = {};
|
|
46
|
+
const timezone = byKey.get("timezone");
|
|
47
|
+
if (typeof timezone === "string") disclosed.timezone = timezone;
|
|
48
|
+
const languages = byKey.get("languages");
|
|
49
|
+
if (languages !== void 0) disclosed.languages = JSON.stringify(languages);
|
|
50
|
+
const architecture = asNumber(byKey.get("architecture"));
|
|
51
|
+
if (architecture !== void 0) disclosed.architecture = architecture;
|
|
52
|
+
for (const key of [
|
|
53
|
+
"cookiesEnabled",
|
|
54
|
+
"sessionStorage",
|
|
55
|
+
"localStorage"
|
|
56
|
+
]) {
|
|
57
|
+
const value = byKey.get(key);
|
|
58
|
+
if (typeof value === "boolean") disclosed[key] = value;
|
|
59
|
+
}
|
|
60
|
+
const bucketId = byKey.get("deviceBucket");
|
|
61
|
+
const colorDepth = asNumber(byKey.get("colorDepth"));
|
|
62
|
+
const hardwareConcurrency = asNumber(byKey.get("hardwareConcurrency"));
|
|
63
|
+
return {
|
|
64
|
+
root: proof.root,
|
|
65
|
+
groupHash: (0, _prosopo_util_crypto.hexHash)(groupInput),
|
|
66
|
+
...typeof bucketId === "string" && bucketId !== "" && { bucketId },
|
|
67
|
+
...colorDepth !== void 0 && { colorDepth },
|
|
68
|
+
...hardwareConcurrency !== void 0 && { hardwareConcurrency },
|
|
69
|
+
...Object.keys(disclosed).length > 0 && { disclosed }
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
//#endregion
|
|
73
|
+
exports.summariseFingerprintProof = summariseFingerprintProof;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import type { UnknownComponents } from "@prosopo/fingerprintjs";
|
|
1
2
|
import { type FingerprintProof } from "./proof.js";
|
|
3
|
+
export declare const forIdentity: (components: UnknownComponents) => UnknownComponents;
|
|
2
4
|
export declare const getFingerprint: () => Promise<string>;
|
|
3
5
|
export declare const getFingerprintProof: (discloseKeys?: readonly string[]) => Promise<FingerprintProof>;
|
|
4
6
|
export declare const prefetchFingerprint: () => void;
|
|
5
7
|
export type { FingerprintLeafDisclosure, FingerprintProof } from "./proof.js";
|
|
6
8
|
export { FINGERPRINT_DISCLOSURE_KEYS, FINGERPRINT_PROOF_VERSION, buildFingerprintProofFromComponents, encodeFingerprintProof, leafHashForContent, verifyFingerprintProofStructure, } from "./proof.js";
|
|
7
9
|
export { buildMerkleLayers, hashMerklePair, merkleProofFromLayers, merkleRootFromLayers, verifyMerkleProof, } from "./merkle.js";
|
|
10
|
+
export type { FingerprintSummary } from "./summary.js";
|
|
11
|
+
export { summariseFingerprintProof } from "./summary.js";
|
|
8
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EACN,KAAK,gBAAgB,EAErB,MAAM,YAAY,CAAC;AAwDpB,eAAO,MAAM,WAAW,eAAgB,iBAAiB,KAAG,iBAK1D,CAAC;AAEH,eAAO,MAAM,cAAc,QAAa,OAAO,CAAC,MAAM,CAMrD,CAAC;AASF,eAAO,MAAM,mBAAmB,kBAChB,SAAS,MAAM,EAAE,KAC9B,OAAO,CAAC,gBAAgB,CAG1B,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAO,IAItC,CAAC;AAEF,YAAY,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EACN,2BAA2B,EAC3B,yBAAyB,EACzB,mCAAmC,EACnC,sBAAsB,EACtB,kBAAkB,EAClB,+BAA+B,GAC/B,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "./_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { buildMerkleLayers, hashMerklePair, merkleProofFromLayers, merkleRootFromLayers, verifyMerkleProof } from "./merkle.js";
|
|
3
3
|
import { FINGERPRINT_DISCLOSURE_KEYS, FINGERPRINT_PROOF_VERSION, buildFingerprintProofFromComponents, encodeFingerprintProof, leafHashForContent, verifyFingerprintProofStructure } from "./proof.js";
|
|
4
|
+
import { summariseFingerprintProof } from "./summary.js";
|
|
4
5
|
//#region src/index.ts
|
|
5
6
|
var EXCLUDED_SOURCES = ["webGlExtensions"];
|
|
6
7
|
var FingerprintJSImport = async () => import("@prosopo/fingerprintjs");
|
|
@@ -19,9 +20,22 @@ var loadComponents = () => {
|
|
|
19
20
|
}
|
|
20
21
|
return componentsCache;
|
|
21
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* Components the visitorId must not be derived from.
|
|
25
|
+
*
|
|
26
|
+
* `deviceBucket` digests components the run already produces, so folding it
|
|
27
|
+
* into the visitorId would add no entropy while changing every existing
|
|
28
|
+
* visitorId. The account address is a pure function of the visitorId, so every
|
|
29
|
+
* account on record would rotate and its sighting history would be orphaned.
|
|
30
|
+
* The proof still commits to it, and it is disclosed, which is the point of
|
|
31
|
+
* collecting it.
|
|
32
|
+
*/
|
|
33
|
+
var NON_IDENTITY_SOURCES = ["deviceBucket"];
|
|
34
|
+
/** Exported so the stability of the visitorId can be asserted directly. */
|
|
35
|
+
var forIdentity = (components) => Object.fromEntries(Object.entries(components).filter(([key]) => !NON_IDENTITY_SOURCES.includes(key)));
|
|
22
36
|
var getFingerprint = async () => {
|
|
23
37
|
const [{ hashComponents }, components] = await Promise.all([FingerprintJSImport(), loadComponents()]);
|
|
24
|
-
return hashComponents(components);
|
|
38
|
+
return hashComponents(forIdentity(components));
|
|
25
39
|
};
|
|
26
40
|
/**
|
|
27
41
|
* Produce a proof of fingerprint: a Merkle commitment to the full component set
|
|
@@ -37,4 +51,4 @@ var prefetchFingerprint = () => {
|
|
|
37
51
|
loadComponents().catch(() => {});
|
|
38
52
|
};
|
|
39
53
|
//#endregion
|
|
40
|
-
export { FINGERPRINT_DISCLOSURE_KEYS, FINGERPRINT_PROOF_VERSION, buildFingerprintProofFromComponents, buildMerkleLayers, encodeFingerprintProof, getFingerprint, getFingerprintProof, hashMerklePair, leafHashForContent, merkleProofFromLayers, merkleRootFromLayers, prefetchFingerprint, verifyFingerprintProofStructure, verifyMerkleProof };
|
|
54
|
+
export { FINGERPRINT_DISCLOSURE_KEYS, FINGERPRINT_PROOF_VERSION, buildFingerprintProofFromComponents, buildMerkleLayers, encodeFingerprintProof, forIdentity, getFingerprint, getFingerprintProof, hashMerklePair, leafHashForContent, merkleProofFromLayers, merkleRootFromLayers, prefetchFingerprint, summariseFingerprintProof, verifyFingerprintProofStructure, verifyMerkleProof };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAEN,mCAAmC,GACnC,MAAM,YAAY,CAAC;AAKpB,MAAM,gBAAgB,GAAG,CAAC,iBAAiB,CAAU,CAAC;AAEtD,MAAM,mBAAmB,GAAG,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC;AAIzE,IAAI,eAAe,GAAsC,IAAI,CAAC;AAE9D,MAAM,cAAc,GAAG,GAA+B,EAAE;IACvD,IAAI,CAAC,eAAe,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;YAC3B,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,GAChD,MAAM,mBAAmB,EAAE,CAAC;YAC7B,MAAM,iBAAiB,EAAE,CAAC;YAG1B,MAAM,aAAa,GAClB;gBACC,KAAK,EAAE,EAAE;aACT,CAAC;YACH,MAAM,aAAa,GAAG,WAAW,CAChC,OAAO,EACP,aAAa,EACb,gBAAgB,CAChB,CAAC;YACF,OAAO,aAAa,EAAE,CAAC;QACxB,CAAC,CAAC,EAAE,CAAC;QACL,eAAe,GAAG,OAAO,CAAC;QAE1B,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE;YAClB,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;gBACjC,eAAe,GAAG,IAAI,CAAC;YACxB,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,eAAe,CAAC;AACxB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAEN,mCAAmC,GACnC,MAAM,YAAY,CAAC;AAKpB,MAAM,gBAAgB,GAAG,CAAC,iBAAiB,CAAU,CAAC;AAEtD,MAAM,mBAAmB,GAAG,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC;AAIzE,IAAI,eAAe,GAAsC,IAAI,CAAC;AAE9D,MAAM,cAAc,GAAG,GAA+B,EAAE;IACvD,IAAI,CAAC,eAAe,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;YAC3B,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,GAChD,MAAM,mBAAmB,EAAE,CAAC;YAC7B,MAAM,iBAAiB,EAAE,CAAC;YAG1B,MAAM,aAAa,GAClB;gBACC,KAAK,EAAE,EAAE;aACT,CAAC;YACH,MAAM,aAAa,GAAG,WAAW,CAChC,OAAO,EACP,aAAa,EACb,gBAAgB,CAChB,CAAC;YACF,OAAO,aAAa,EAAE,CAAC;QACxB,CAAC,CAAC,EAAE,CAAC;QACL,eAAe,GAAG,OAAO,CAAC;QAE1B,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE;YAClB,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;gBACjC,eAAe,GAAG,IAAI,CAAC;YACxB,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,eAAe,CAAC;AACxB,CAAC,CAAC;AAYF,MAAM,oBAAoB,GAAsB,CAAC,cAAc,CAAC,CAAC;AAGjE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,UAA6B,EAAqB,EAAE,CAC/E,MAAM,CAAC,WAAW,CACjB,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,CAChC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,oBAAoB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAC9C,CACD,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,IAAqB,EAAE;IACzD,MAAM,CAAC,EAAE,cAAc,EAAE,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC1D,mBAAmB,EAAE;QACrB,cAAc,EAAE;KAChB,CAAC,CAAC;IACH,OAAO,cAAc,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC;AAChD,CAAC,CAAC;AASF,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EACvC,YAAgC,EACJ,EAAE;IAC9B,MAAM,UAAU,GAAG,MAAM,cAAc,EAAE,CAAC;IAC1C,OAAO,mCAAmC,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;AACtE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAS,EAAE;IAC7C,cAAc,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;IAE5B,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC;AAGF,OAAO,EACN,2BAA2B,EAC3B,yBAAyB,EACzB,mCAAmC,EACnC,sBAAsB,EACtB,kBAAkB,EAClB,+BAA+B,GAC/B,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { hashComponents } from "@prosopo/fingerprintjs";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { forIdentity } from "./index.js";
|
|
4
|
+
const asComponents = (values) => Object.fromEntries(Object.entries(values).map(([key, value]) => [key, { value, duration: 1 }]));
|
|
5
|
+
describe("forIdentity", () => {
|
|
6
|
+
const device = {
|
|
7
|
+
platform: "MacIntel",
|
|
8
|
+
fonts: ["Arial"],
|
|
9
|
+
audio: 1.5,
|
|
10
|
+
};
|
|
11
|
+
const withBucket = {
|
|
12
|
+
...device,
|
|
13
|
+
deviceBucket: "9f1c3a0e",
|
|
14
|
+
};
|
|
15
|
+
it("leaves the visitorId where it was before deviceBucket existed", () => {
|
|
16
|
+
expect(hashComponents(forIdentity(asComponents(withBucket)))).toBe(hashComponents(asComponents(device)));
|
|
17
|
+
});
|
|
18
|
+
it("would have moved it without the exclusion", () => {
|
|
19
|
+
expect(hashComponents(asComponents(withBucket))).not.toBe(hashComponents(asComponents(device)));
|
|
20
|
+
});
|
|
21
|
+
it("keeps every other component", () => {
|
|
22
|
+
expect(Object.keys(forIdentity(asComponents(withBucket)))).toStrictEqual(Object.keys(device));
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"AAcA,OAAO,EAA0B,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,YAAY,GAAG,CAAC,MAA+B,EAAqB,EAAE,CAC3E,MAAM,CAAC,WAAW,CACjB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAC3E,CAAC;AAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC5B,MAAM,MAAM,GAA4B;QACvC,QAAQ,EAAE,UAAU;QACpB,KAAK,EAAE,CAAC,OAAO,CAAC;QAChB,KAAK,EAAE,GAAG;KACV,CAAC;IACF,MAAM,UAAU,GAA4B;QAC3C,GAAG,MAAM;QACT,YAAY,EAAE,UAAU;KACxB,CAAC;IAEF,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACxE,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CACjE,cAAc,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CACpC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,cAAc,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CACxD,cAAc,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CACpC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CACvE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CACnB,CAAC;IACH,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
package/dist/proof.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proof.d.ts","sourceRoot":"","sources":["../src/proof.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAa,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AASlD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAa3C,eAAO,MAAM,2BAA2B,EAAE,SAAS,MAAM,
|
|
1
|
+
{"version":3,"file":"proof.d.ts","sourceRoot":"","sources":["../src/proof.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAa,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AASlD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAa3C,eAAO,MAAM,2BAA2B,EAAE,SAAS,MAAM,EAaxD,CAAC;AASF,MAAM,WAAW,yBAAyB;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,WAAW,CAAC;CACnB;AASD,MAAM,WAAW,gBAAgB;IAChC,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,yBAAyB,EAAE,CAAC;CACzC;AA2BD,eAAO,MAAM,kBAAkB,YAAa,MAAM,KAAG,MAA0B,CAAC;AAShF,eAAO,MAAM,mCAAmC,eACnC,iBAAiB,iBACd,SAAS,MAAM,EAAE,KAC9B,gBAsCF,CAAC;AAQF,eAAO,MAAM,+BAA+B,UACpC,gBAAgB,KACrB,OAkBF,CAAC;AAEF,eAAO,MAAM,sBAAsB,UAAW,gBAAgB,KAAG,MAC3C,CAAC"}
|
package/dist/proof.js
CHANGED
|
@@ -21,7 +21,8 @@ var FINGERPRINT_DISCLOSURE_KEYS = [
|
|
|
21
21
|
"timezone",
|
|
22
22
|
"hardwareConcurrency",
|
|
23
23
|
"languages",
|
|
24
|
-
"architecture"
|
|
24
|
+
"architecture",
|
|
25
|
+
"deviceBucket"
|
|
25
26
|
];
|
|
26
27
|
var escapeKey = (key) => key.replace(/([:|\\])/g, "\\$1");
|
|
27
28
|
var componentLeafContent = (key, component) => {
|
package/dist/proof.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proof.js","sourceRoot":"","sources":["../src/proof.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EACN,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,GACjB,MAAM,aAAa,CAAC;AAErB,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAa3C,MAAM,CAAC,MAAM,2BAA2B,GAAsB;IAC7D,YAAY;IACZ,gBAAgB;IAChB,gBAAgB;IAChB,cAAc;IACd,UAAU;IACV,qBAAqB;IACrB,WAAW;IACX,cAAc;CACd,CAAC;AA+BF,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AAK5E,MAAM,oBAAoB,GAAG,CAC5B,GAAW,EACX,SAA6B,EACpB,EAAE;IACX,MAAM,UAAU,GACf,OAAO,IAAI,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAClE,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,UAAU,EAAE,CAAC;AAC1C,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAC7B,UAAqC,EAC5B,EAAE;IACX,MAAM,UAAU,GAAG,UAAU,CAAC,KAAK;QAClC,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,UAAU,EAAE,CAAC;AACrD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,OAAe,EAAU,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAShF,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAClD,UAA6B,EAC7B,YAAgC,EACb,EAAE;IACrB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACnC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,wCAAwC,GAAG,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,kBAAkB,CAAC,oBAAoB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAE1C,MAAM,QAAQ,GAAG,YAAY,IAAI,IAAI,CAAC;IACtC,MAAM,WAAW,GAAgC,EAAE,CAAC;IACpD,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YAClB,SAAS;QACV,CAAC;QACD,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,SAAS,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YACvD,SAAS;QACV,CAAC;QACD,MAAM,KAAK,GAAG,qBAAqB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACtD,WAAW,CAAC,IAAI,CACf,OAAO,IAAI,SAAS;YACnB,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE;YAC7B,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,CACzC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,CAAC,EAAE,yBAAyB,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAC5D,CAAC,CAAC;AAQF,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAC9C,KAAuB,EACb,EAAE;IACZ,IAAI,KAAK,CAAC,CAAC,KAAK,yBAAyB,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACd,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtE,OAAO,KAAK,CAAC;IACd,CAAC;IACD,KAAK,MAAM,UAAU,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,kBAAkB,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC,CAAC;QACvE,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACpD,OAAO,KAAK,CAAC;QACd,CAAC;QACD,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAChE,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;YAC5D,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAAuB,EAAU,EAAE,CACzE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"proof.js","sourceRoot":"","sources":["../src/proof.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { FingerprintDisclosedValuesStored, FingerprintSummaryStored } from "@prosopo/types";
|
|
2
|
+
export type FingerprintSummary = FingerprintSummaryStored;
|
|
3
|
+
export type FingerprintDisclosedValues = FingerprintDisclosedValuesStored;
|
|
4
|
+
export declare const summariseFingerprintProof: (encoded: string | undefined) => FingerprintSummary | undefined;
|
|
5
|
+
//# sourceMappingURL=summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../src/summary.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACX,gCAAgC,EAChC,wBAAwB,EACxB,MAAM,gBAAgB,CAAC;AAwBxB,MAAM,MAAM,kBAAkB,GAAG,wBAAwB,CAAC;AAC1D,MAAM,MAAM,0BAA0B,GAAG,gCAAgC,CAAC;AAgB1E,eAAO,MAAM,yBAAyB,YAC5B,MAAM,GAAG,SAAS,KACzB,kBAAkB,GAAG,SA8DvB,CAAC"}
|
package/dist/summary.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { verifyFingerprintProofStructure } from "./proof.js";
|
|
2
|
+
import { hexHash } from "@prosopo/util-crypto";
|
|
3
|
+
//#region src/summary.ts
|
|
4
|
+
/**
|
|
5
|
+
* The disclosed keys that are fixed by the installation and the host. A hash
|
|
6
|
+
* over them names a cohort of devices.
|
|
7
|
+
*
|
|
8
|
+
* `colorDepth` and `hardwareConcurrency` are disclosed too but kept out of the
|
|
9
|
+
* hash and stored beside it, so that the values can be read per cohort rather
|
|
10
|
+
* than only folded into it.
|
|
11
|
+
*/
|
|
12
|
+
var GROUP_KEYS = [
|
|
13
|
+
"cookiesEnabled",
|
|
14
|
+
"sessionStorage",
|
|
15
|
+
"localStorage",
|
|
16
|
+
"timezone",
|
|
17
|
+
"languages",
|
|
18
|
+
"architecture"
|
|
19
|
+
];
|
|
20
|
+
var asNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
21
|
+
/**
|
|
22
|
+
* Reduce an encoded proof to the fields worth storing, or `undefined` when it
|
|
23
|
+
* is absent, unparseable, or fails structural verification.
|
|
24
|
+
*
|
|
25
|
+
* Structural verification is not optional here: an unverified disclosure is a
|
|
26
|
+
* client-asserted value with a decorative Merkle path beside it, and storing
|
|
27
|
+
* one would put a forgeable field into an aggregation that reads as
|
|
28
|
+
* tamper-evident. Whether the values are *plausible* is a separate concern and
|
|
29
|
+
* stays in the routing machine's validator; this only refuses what does not
|
|
30
|
+
* hash together.
|
|
31
|
+
*/
|
|
32
|
+
var summariseFingerprintProof = (encoded) => {
|
|
33
|
+
if (!encoded) return void 0;
|
|
34
|
+
let proof;
|
|
35
|
+
try {
|
|
36
|
+
proof = JSON.parse(encoded);
|
|
37
|
+
} catch {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (typeof proof !== "object" || proof === null || typeof proof.root !== "string" || !Array.isArray(proof.disclosures)) return;
|
|
41
|
+
if (!verifyFingerprintProofStructure(proof)) return void 0;
|
|
42
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
43
|
+
for (const disclosure of proof.disclosures) if (!disclosure.error) byKey.set(disclosure.key, disclosure.value);
|
|
44
|
+
const groupInput = GROUP_KEYS.map((key) => `${key}:${JSON.stringify(byKey.get(key) ?? null)}`).join("|");
|
|
45
|
+
const disclosed = {};
|
|
46
|
+
const timezone = byKey.get("timezone");
|
|
47
|
+
if (typeof timezone === "string") disclosed.timezone = timezone;
|
|
48
|
+
const languages = byKey.get("languages");
|
|
49
|
+
if (languages !== void 0) disclosed.languages = JSON.stringify(languages);
|
|
50
|
+
const architecture = asNumber(byKey.get("architecture"));
|
|
51
|
+
if (architecture !== void 0) disclosed.architecture = architecture;
|
|
52
|
+
for (const key of [
|
|
53
|
+
"cookiesEnabled",
|
|
54
|
+
"sessionStorage",
|
|
55
|
+
"localStorage"
|
|
56
|
+
]) {
|
|
57
|
+
const value = byKey.get(key);
|
|
58
|
+
if (typeof value === "boolean") disclosed[key] = value;
|
|
59
|
+
}
|
|
60
|
+
const bucketId = byKey.get("deviceBucket");
|
|
61
|
+
const colorDepth = asNumber(byKey.get("colorDepth"));
|
|
62
|
+
const hardwareConcurrency = asNumber(byKey.get("hardwareConcurrency"));
|
|
63
|
+
return {
|
|
64
|
+
root: proof.root,
|
|
65
|
+
groupHash: hexHash(groupInput),
|
|
66
|
+
...typeof bucketId === "string" && bucketId !== "" && { bucketId },
|
|
67
|
+
...colorDepth !== void 0 && { colorDepth },
|
|
68
|
+
...hardwareConcurrency !== void 0 && { hardwareConcurrency },
|
|
69
|
+
...Object.keys(disclosed).length > 0 && { disclosed }
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
//#endregion
|
|
73
|
+
export { summariseFingerprintProof };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../src/summary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.test.d.ts","sourceRoot":"","sources":["../src/summary.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { FINGERPRINT_DISCLOSURE_KEYS, buildFingerprintProofFromComponents, encodeFingerprintProof, } from "./proof.js";
|
|
3
|
+
import { summariseFingerprintProof } from "./summary.js";
|
|
4
|
+
const HEX_HASH = /^0x[0-9a-f]{64}$/;
|
|
5
|
+
const components = (overrides = {}) => {
|
|
6
|
+
const base = {
|
|
7
|
+
colorDepth: 24,
|
|
8
|
+
cookiesEnabled: true,
|
|
9
|
+
sessionStorage: true,
|
|
10
|
+
localStorage: true,
|
|
11
|
+
timezone: "Europe/London",
|
|
12
|
+
hardwareConcurrency: 8,
|
|
13
|
+
languages: [["en-GB"], ["en"]],
|
|
14
|
+
architecture: 255,
|
|
15
|
+
platform: "MacIntel",
|
|
16
|
+
screenResolution: [1920, 1080],
|
|
17
|
+
deviceBucket: "a1b2c3d4e5f60718293a4b5c6d7e8f90",
|
|
18
|
+
audio: 124.04347527516074,
|
|
19
|
+
...overrides,
|
|
20
|
+
};
|
|
21
|
+
return Object.fromEntries(Object.entries(base).map(([k, v]) => [k, { value: v, duration: 1 }]));
|
|
22
|
+
};
|
|
23
|
+
const summarise = (overrides = {}) => summariseFingerprintProof(encodeFingerprintProof(buildFingerprintProofFromComponents(components(overrides), FINGERPRINT_DISCLOSURE_KEYS)));
|
|
24
|
+
describe("summariseFingerprintProof", () => {
|
|
25
|
+
it("keeps the root, the group hash and the two moving values", () => {
|
|
26
|
+
const summary = summarise();
|
|
27
|
+
expect(summary?.root).toMatch(HEX_HASH);
|
|
28
|
+
expect(summary?.groupHash).toMatch(HEX_HASH);
|
|
29
|
+
expect(summary?.colorDepth).toBe(24);
|
|
30
|
+
expect(summary?.hardwareConcurrency).toBe(8);
|
|
31
|
+
});
|
|
32
|
+
it("holds the group hash steady when only colorDepth and cores differ", () => {
|
|
33
|
+
const a = summarise({ colorDepth: 24, hardwareConcurrency: 8 });
|
|
34
|
+
const b = summarise({ colorDepth: 30, hardwareConcurrency: 10 });
|
|
35
|
+
expect(a?.groupHash).toBe(b?.groupHash);
|
|
36
|
+
expect(a?.colorDepth).not.toBe(b?.colorDepth);
|
|
37
|
+
expect(a?.hardwareConcurrency).not.toBe(b?.hardwareConcurrency);
|
|
38
|
+
});
|
|
39
|
+
it("keeps the grouped values beside their hash", () => {
|
|
40
|
+
const summary = summarise();
|
|
41
|
+
expect(summary?.disclosed).toStrictEqual({
|
|
42
|
+
timezone: "Europe/London",
|
|
43
|
+
languages: '[["en-GB"],["en"]]',
|
|
44
|
+
architecture: 255,
|
|
45
|
+
cookiesEnabled: true,
|
|
46
|
+
sessionStorage: true,
|
|
47
|
+
localStorage: true,
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
it("omits a disclosed value of the wrong type rather than coercing it", () => {
|
|
51
|
+
const summary = summarise({ architecture: "sixty-four", timezone: 42 });
|
|
52
|
+
expect(summary?.disclosed?.architecture).toBeUndefined();
|
|
53
|
+
expect(summary?.disclosed?.timezone).toBeUndefined();
|
|
54
|
+
expect(summary?.disclosed?.cookiesEnabled).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
it("moves the group hash when a grouped value differs", () => {
|
|
57
|
+
const a = summarise({ timezone: "Europe/London" });
|
|
58
|
+
const b = summarise({ timezone: "America/New_York" });
|
|
59
|
+
expect(a?.groupHash).not.toBe(b?.groupHash);
|
|
60
|
+
});
|
|
61
|
+
it("gives a fresh root when only an undisclosed component changed", () => {
|
|
62
|
+
const a = summarise({ audio: 1 });
|
|
63
|
+
const b = summarise({ audio: 2 });
|
|
64
|
+
expect(a?.root).not.toBe(b?.root);
|
|
65
|
+
expect(a?.groupHash).toBe(b?.groupHash);
|
|
66
|
+
expect(a?.colorDepth).toBe(b?.colorDepth);
|
|
67
|
+
});
|
|
68
|
+
it("carries the bucketId from the proven disclosure", () => {
|
|
69
|
+
const summary = summarise();
|
|
70
|
+
expect(summary?.bucketId).toBe("a1b2c3d4e5f60718293a4b5c6d7e8f90");
|
|
71
|
+
});
|
|
72
|
+
it("reveals nothing but the digest — no platform, screen or fonts", () => {
|
|
73
|
+
const encoded = encodeFingerprintProof(buildFingerprintProofFromComponents(components(), FINGERPRINT_DISCLOSURE_KEYS));
|
|
74
|
+
expect(encoded).not.toContain("MacIntel");
|
|
75
|
+
expect(encoded).not.toContain("1920");
|
|
76
|
+
expect(summariseFingerprintProof(encoded)?.bucketId).toBeDefined();
|
|
77
|
+
});
|
|
78
|
+
it("holds the bucketId steady when only the exit region moves", () => {
|
|
79
|
+
const a = summarise({
|
|
80
|
+
timezone: "Europe/London",
|
|
81
|
+
languages: [["en-GB"], ["en"]],
|
|
82
|
+
});
|
|
83
|
+
const b = summarise({
|
|
84
|
+
timezone: "Asia/Tokyo",
|
|
85
|
+
languages: [["ja-JP"], ["ja"]],
|
|
86
|
+
});
|
|
87
|
+
expect(a?.bucketId).toBe(b?.bucketId);
|
|
88
|
+
expect(a?.groupHash).not.toBe(b?.groupHash);
|
|
89
|
+
});
|
|
90
|
+
it("moves the bucketId when the device digest differs", () => {
|
|
91
|
+
const a = summarise({ deviceBucket: "a".repeat(32) });
|
|
92
|
+
const b = summarise({ deviceBucket: "b".repeat(32) });
|
|
93
|
+
expect(a?.bucketId).not.toBe(b?.bucketId);
|
|
94
|
+
});
|
|
95
|
+
it("keeps the bucketId while the account-bearing root churns", () => {
|
|
96
|
+
const a = summarise({ audio: 1 });
|
|
97
|
+
const b = summarise({ audio: 2 });
|
|
98
|
+
expect(a?.root).not.toBe(b?.root);
|
|
99
|
+
expect(a?.bucketId).toBe(b?.bucketId);
|
|
100
|
+
});
|
|
101
|
+
it("refuses a bucketId built on a tampered disclosure", () => {
|
|
102
|
+
const proof = buildFingerprintProofFromComponents(components(), FINGERPRINT_DISCLOSURE_KEYS);
|
|
103
|
+
const tampered = JSON.parse(JSON.stringify(proof));
|
|
104
|
+
tampered.disclosures.find((d) => d.key === "deviceBucket").value = "f".repeat(32);
|
|
105
|
+
expect(summariseFingerprintProof(JSON.stringify(tampered))).toBeUndefined();
|
|
106
|
+
});
|
|
107
|
+
it("omits the bucketId when the client did not disclose one", () => {
|
|
108
|
+
const proof = buildFingerprintProofFromComponents(components(), [
|
|
109
|
+
"timezone",
|
|
110
|
+
"languages",
|
|
111
|
+
]);
|
|
112
|
+
const summary = summariseFingerprintProof(encodeFingerprintProof(proof));
|
|
113
|
+
expect(summary).toBeDefined();
|
|
114
|
+
expect(summary?.bucketId).toBeUndefined();
|
|
115
|
+
});
|
|
116
|
+
it("returns undefined for an absent proof", () => {
|
|
117
|
+
expect(summariseFingerprintProof(undefined)).toBeUndefined();
|
|
118
|
+
expect(summariseFingerprintProof("")).toBeUndefined();
|
|
119
|
+
});
|
|
120
|
+
it("returns undefined for a proof that is not JSON", () => {
|
|
121
|
+
expect(summariseFingerprintProof("invalid-fingerprint-proof")).toBeUndefined();
|
|
122
|
+
});
|
|
123
|
+
it("refuses a proof whose disclosure does not hash to the root", () => {
|
|
124
|
+
const proof = buildFingerprintProofFromComponents(components(), FINGERPRINT_DISCLOSURE_KEYS);
|
|
125
|
+
const tampered = JSON.parse(JSON.stringify(proof));
|
|
126
|
+
const target = tampered.disclosures.find((d) => d.key === "hardwareConcurrency");
|
|
127
|
+
target.value = 64;
|
|
128
|
+
expect(summariseFingerprintProof(JSON.stringify(tampered))).toBeUndefined();
|
|
129
|
+
});
|
|
130
|
+
it("refuses a proof whose root has been swapped", () => {
|
|
131
|
+
const proof = buildFingerprintProofFromComponents(components(), FINGERPRINT_DISCLOSURE_KEYS);
|
|
132
|
+
const tampered = JSON.parse(JSON.stringify(proof));
|
|
133
|
+
tampered.root = `0x${"0".repeat(64)}`;
|
|
134
|
+
expect(summariseFingerprintProof(JSON.stringify(tampered))).toBeUndefined();
|
|
135
|
+
});
|
|
136
|
+
it("omits a moving value that is not a finite number", () => {
|
|
137
|
+
const summary = summarise({ hardwareConcurrency: "eight" });
|
|
138
|
+
expect(summary).toBeDefined();
|
|
139
|
+
expect(summary?.hardwareConcurrency).toBeUndefined();
|
|
140
|
+
expect(summary?.colorDepth).toBe(24);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
//# sourceMappingURL=summary.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.test.js","sourceRoot":"","sources":["../src/summary.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosopo/fingerprint",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "Provider fingerprint",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"import": "./dist/index.js",
|
|
15
15
|
"require": "./dist/cjs/index.cjs"
|
|
16
|
+
},
|
|
17
|
+
"./summary": {
|
|
18
|
+
"types": "./dist/summary.d.ts",
|
|
19
|
+
"import": "./dist/summary.js",
|
|
20
|
+
"require": "./dist/cjs/summary.cjs"
|
|
16
21
|
}
|
|
17
22
|
},
|
|
18
23
|
"repository": {
|
|
@@ -28,23 +33,23 @@
|
|
|
28
33
|
"homepage": "https://github.com/prosopo/captcha#readme",
|
|
29
34
|
"dependencies": {
|
|
30
35
|
"@prosopo/fingerprintjs": "5.2.0",
|
|
31
|
-
"@prosopo/types": "5.
|
|
32
|
-
"@prosopo/util-crypto": "13.6.
|
|
36
|
+
"@prosopo/types": "5.17.0",
|
|
37
|
+
"@prosopo/util-crypto": "13.6.1"
|
|
33
38
|
},
|
|
34
39
|
"devDependencies": {
|
|
35
|
-
"@prosopo/config": "3.
|
|
40
|
+
"@prosopo/config": "3.5.0",
|
|
36
41
|
"@types/node": "22.10.2",
|
|
37
|
-
"@vitest/coverage-v8": "
|
|
42
|
+
"@vitest/coverage-v8": "5.0.4",
|
|
38
43
|
"concurrently": "9.0.1",
|
|
39
44
|
"del-cli": "6.0.0",
|
|
40
|
-
"dotenv": "
|
|
45
|
+
"dotenv": "18.0.7",
|
|
41
46
|
"npm-run-all": "4.1.5",
|
|
42
47
|
"rimraf": "6.0.1",
|
|
43
48
|
"tslib": "2.7.0",
|
|
44
49
|
"tsx": "4.20.3",
|
|
45
50
|
"typescript": "5.6.2",
|
|
46
|
-
"vite": "8.1.
|
|
47
|
-
"vitest": "
|
|
51
|
+
"vite": "8.1.6",
|
|
52
|
+
"vitest": "5.0.4"
|
|
48
53
|
},
|
|
49
54
|
"sideEffects": false,
|
|
50
55
|
"scripts": {
|