@prosopo/fingerprint 2.7.18 → 2.7.20
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 +11 -9
- package/.turbo/turbo-build$colon$tsc.log +10 -10
- package/.turbo/turbo-build.log +13 -10
- package/CHANGELOG.md +18 -0
- package/dist/_virtual/_rolldown/runtime.js +3 -0
- package/dist/cjs/index.cjs +46 -74
- package/dist/cjs/merkle.cjs +64 -74
- package/dist/cjs/proof.cjs +91 -73
- package/dist/index.js +35 -56
- package/dist/merkle.js +64 -78
- package/dist/proof.js +90 -78
- package/package.json +6 -6
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/fingerprint@2.7.
|
|
2
|
+
> @prosopo/fingerprint@2.7.20 build:cjs
|
|
3
3
|
> NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
|
|
4
4
|
|
|
5
5
|
ViteCommonJSConfig: .
|
|
@@ -21,13 +21,15 @@ ViteCommonJSConfig: .
|
|
|
21
21
|
'@prosopo/util-crypto'
|
|
22
22
|
]
|
|
23
23
|
}
|
|
24
|
-
[
|
|
24
|
+
[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
|
|
25
|
+
[36mvite v8.1.5 [32mbuilding ssr environment for production...[36m[39m
|
|
25
26
|
Bundle build started
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
[32m✓[39m 3 modules transformed.
|
|
27
|
+
[2K
|
|
28
|
+
✓ 4 modules transformed.
|
|
29
29
|
rendering chunks...
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
computing gzip size...
|
|
31
|
+
dist/cjs/index.cjs 2.50 kB │ gzip: 0.89 kB
|
|
32
|
+
dist/cjs/merkle.cjs 2.84 kB │ gzip: 1.09 kB
|
|
33
|
+
dist/cjs/proof.cjs 4.31 kB │ gzip: 1.70 kB
|
|
34
|
+
|
|
35
|
+
[32m✓ built in 60ms[39m
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/fingerprint@2.7.
|
|
2
|
+
> @prosopo/fingerprint@2.7.20 build:tsc
|
|
3
3
|
> tsc --build --verbose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
11:09:46 AM - Projects in this build:
|
|
6
6
|
* ../../dev/config/tsconfig.json
|
|
7
7
|
* ../fingerprintjs/tsconfig.json
|
|
8
8
|
* ../locale/tsconfig.json
|
|
@@ -11,19 +11,19 @@
|
|
|
11
11
|
* ../types/tsconfig.json
|
|
12
12
|
* tsconfig.json
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
11:09:46 AM - 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'
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
11:09:46 AM - Project '../fingerprintjs/tsconfig.json' is up to date because newest input '../fingerprintjs/src/utils/browser.ts' is older than output '../fingerprintjs/tsconfig.tsbuildinfo'
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
11:09:46 AM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
11:09:46 AM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
11:09:47 AM - 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'
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
11:09:47 AM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/types.test-d.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
11:09:47 AM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
11:09:47 AM - Building project '/home/runner/work/captcha/captcha/packages/fingerprint/tsconfig.json'...
|
|
29
29
|
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/fingerprint@2.7.
|
|
2
|
+
> @prosopo/fingerprint@2.7.20 build
|
|
3
3
|
> npm run build:cross-env -- --mode ${NODE_ENV:-development}
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @prosopo/fingerprint@2.7.
|
|
6
|
+
> @prosopo/fingerprint@2.7.20 build:cross-env
|
|
7
7
|
> vite build --config vite.esm.config.ts --mode production
|
|
8
8
|
|
|
9
9
|
ViteEsmConfig: .
|
|
@@ -25,13 +25,16 @@ ViteEsmConfig: .
|
|
|
25
25
|
'@prosopo/util-crypto'
|
|
26
26
|
]
|
|
27
27
|
}
|
|
28
|
-
[
|
|
28
|
+
[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
|
|
29
|
+
[36mvite v8.1.5 [32mbuilding ssr environment for production...[36m[39m
|
|
29
30
|
Bundle build started
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
[32m✓[39m 3 modules transformed.
|
|
31
|
+
[2K
|
|
32
|
+
✓ 4 modules transformed.
|
|
33
33
|
rendering chunks...
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
computing gzip size...
|
|
35
|
+
dist/_virtual/_rolldown/runtime.js 0.04 kB │ gzip: 0.06 kB
|
|
36
|
+
dist/index.js 2.06 kB │ gzip: 0.81 kB
|
|
37
|
+
dist/merkle.js 2.68 kB │ gzip: 1.06 kB
|
|
38
|
+
dist/proof.js 4.03 kB │ gzip: 1.66 kB
|
|
39
|
+
|
|
40
|
+
[32m✓ built in 77ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @prosopo/fingerprint
|
|
2
2
|
|
|
3
|
+
## 2.7.20
|
|
4
|
+
### Patch Changes
|
|
5
|
+
|
|
6
|
+
- Updated dependencies [787017b]
|
|
7
|
+
- Updated dependencies [787017b]
|
|
8
|
+
- Updated dependencies [787017b]
|
|
9
|
+
- Updated dependencies [6f19cde]
|
|
10
|
+
- @prosopo/types@5.0.0
|
|
11
|
+
|
|
12
|
+
## 2.7.19
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- e14fce6: chore(deps): bump vite to 6.4.3 and mongoose to 8.24.1, and adjust types for the mongoose 8.24 Document/ObjectId changes
|
|
16
|
+
- Updated dependencies [103318c]
|
|
17
|
+
- Updated dependencies [270a8d8]
|
|
18
|
+
- Updated dependencies [e14fce6]
|
|
19
|
+
- @prosopo/types@4.10.0
|
|
20
|
+
|
|
3
21
|
## 2.7.18
|
|
4
22
|
### Patch Changes
|
|
5
23
|
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,82 +1,54 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
-
for (let key of __getOwnPropNames(from))
|
|
11
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
-
}
|
|
14
|
-
return to;
|
|
15
|
-
};
|
|
16
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
-
mod
|
|
23
|
-
));
|
|
24
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
})();
|
|
45
|
-
componentsCache = pending;
|
|
46
|
-
pending.catch(() => {
|
|
47
|
-
if (componentsCache === pending) {
|
|
48
|
-
componentsCache = null;
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
return componentsCache;
|
|
2
|
+
const require_merkle = require("./merkle.cjs");
|
|
3
|
+
const require_proof = require("./proof.cjs");
|
|
4
|
+
//#region src/index.ts
|
|
5
|
+
var EXCLUDED_SOURCES = ["webGlExtensions"];
|
|
6
|
+
var FingerprintJSImport = async () => import("@prosopo/fingerprintjs");
|
|
7
|
+
var componentsCache = null;
|
|
8
|
+
var loadComponents = () => {
|
|
9
|
+
if (!componentsCache) {
|
|
10
|
+
const pending = (async () => {
|
|
11
|
+
const { sources, loadSources, prepareForSources } = await FingerprintJSImport();
|
|
12
|
+
await prepareForSources();
|
|
13
|
+
return loadSources(sources, { cache: {} }, EXCLUDED_SOURCES)();
|
|
14
|
+
})();
|
|
15
|
+
componentsCache = pending;
|
|
16
|
+
pending.catch(() => {
|
|
17
|
+
if (componentsCache === pending) componentsCache = null;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return componentsCache;
|
|
53
21
|
};
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
loadComponents()
|
|
58
|
-
]);
|
|
59
|
-
return hashComponents(components);
|
|
22
|
+
var getFingerprint = async () => {
|
|
23
|
+
const [{ hashComponents }, components] = await Promise.all([FingerprintJSImport(), loadComponents()]);
|
|
24
|
+
return hashComponents(components);
|
|
60
25
|
};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Produce a proof of fingerprint: a Merkle commitment to the full component set
|
|
28
|
+
* plus a selective disclosure of the requested components. Callers should pass
|
|
29
|
+
* {@link FINGERPRINT_DISCLOSURE_KEYS} — omitting `discloseKeys` discloses every
|
|
30
|
+
* component, which produces a very large payload. Derived from the same
|
|
31
|
+
* component run as {@link getFingerprint}.
|
|
32
|
+
*/
|
|
33
|
+
var getFingerprintProof = async (discloseKeys) => {
|
|
34
|
+
const components = await loadComponents();
|
|
35
|
+
return require_proof.buildFingerprintProofFromComponents(components, discloseKeys);
|
|
64
36
|
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
});
|
|
37
|
+
var prefetchFingerprint = () => {
|
|
38
|
+
loadComponents().catch(() => {});
|
|
68
39
|
};
|
|
69
|
-
|
|
70
|
-
exports.
|
|
71
|
-
exports.
|
|
72
|
-
exports.
|
|
73
|
-
exports.
|
|
74
|
-
exports.
|
|
75
|
-
exports.buildMerkleLayers = merkle.buildMerkleLayers;
|
|
76
|
-
exports.hashMerklePair = merkle.hashMerklePair;
|
|
77
|
-
exports.merkleProofFromLayers = merkle.merkleProofFromLayers;
|
|
78
|
-
exports.merkleRootFromLayers = merkle.merkleRootFromLayers;
|
|
79
|
-
exports.verifyMerkleProof = merkle.verifyMerkleProof;
|
|
40
|
+
//#endregion
|
|
41
|
+
exports.FINGERPRINT_DISCLOSURE_KEYS = require_proof.FINGERPRINT_DISCLOSURE_KEYS;
|
|
42
|
+
exports.FINGERPRINT_PROOF_VERSION = require_proof.FINGERPRINT_PROOF_VERSION;
|
|
43
|
+
exports.buildFingerprintProofFromComponents = require_proof.buildFingerprintProofFromComponents;
|
|
44
|
+
exports.buildMerkleLayers = require_merkle.buildMerkleLayers;
|
|
45
|
+
exports.encodeFingerprintProof = require_proof.encodeFingerprintProof;
|
|
80
46
|
exports.getFingerprint = getFingerprint;
|
|
81
47
|
exports.getFingerprintProof = getFingerprintProof;
|
|
48
|
+
exports.hashMerklePair = require_merkle.hashMerklePair;
|
|
49
|
+
exports.leafHashForContent = require_proof.leafHashForContent;
|
|
50
|
+
exports.merkleProofFromLayers = require_merkle.merkleProofFromLayers;
|
|
51
|
+
exports.merkleRootFromLayers = require_merkle.merkleRootFromLayers;
|
|
82
52
|
exports.prefetchFingerprint = prefetchFingerprint;
|
|
53
|
+
exports.verifyFingerprintProofStructure = require_proof.verifyFingerprintProofStructure;
|
|
54
|
+
exports.verifyMerkleProof = require_merkle.verifyMerkleProof;
|
package/dist/cjs/merkle.cjs
CHANGED
|
@@ -1,81 +1,71 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
throw new Error(
|
|
8
|
-
`merkle: index ${index} out of range (length ${arr.length})`
|
|
9
|
-
);
|
|
10
|
-
}
|
|
11
|
-
return value;
|
|
1
|
+
let _prosopo_util_crypto = require("@prosopo/util-crypto");
|
|
2
|
+
//#region src/merkle.ts
|
|
3
|
+
var at = (arr, index) => {
|
|
4
|
+
const value = arr[index];
|
|
5
|
+
if (value === void 0) throw new Error(`merkle: index ${index} out of range (length ${arr.length})`);
|
|
6
|
+
return value;
|
|
12
7
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
8
|
+
/** Hash a pair of child hashes into their parent. */
|
|
9
|
+
var hashMerklePair = (left, right) => (0, _prosopo_util_crypto.hexHashArray)([left, right]);
|
|
10
|
+
/**
|
|
11
|
+
* Build every layer of the Merkle tree, bottom-up. Layer 0 is the leaf hashes,
|
|
12
|
+
* the final layer is `[root]`. An odd node at the end of a layer is paired with
|
|
13
|
+
* itself.
|
|
14
|
+
*/
|
|
15
|
+
var buildMerkleLayers = (leafHashes) => {
|
|
16
|
+
if (leafHashes.length === 0) throw new Error("merkle: cannot build a tree with no leaves");
|
|
17
|
+
const layers = [[...leafHashes]];
|
|
18
|
+
let current = leafHashes;
|
|
19
|
+
while (current.length > 1) {
|
|
20
|
+
const next = [];
|
|
21
|
+
for (let i = 0; i < current.length; i += 2) {
|
|
22
|
+
const left = at(current, i);
|
|
23
|
+
const right = i + 1 < current.length ? at(current, i + 1) : left;
|
|
24
|
+
next.push(hashMerklePair(left, right));
|
|
25
|
+
}
|
|
26
|
+
layers.push(next);
|
|
27
|
+
current = next;
|
|
28
|
+
}
|
|
29
|
+
return layers;
|
|
31
30
|
};
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
hash = hashMerklePair(pair[0], pair[1]);
|
|
50
|
-
}
|
|
51
|
-
return [...proof, [merkleRootFromLayers(layers)]];
|
|
31
|
+
var merkleRootFromLayers = (layers) => at(at(layers, layers.length - 1), 0);
|
|
32
|
+
/** Produce the sibling path proving `leafHash` belongs to the tree. */
|
|
33
|
+
var merkleProofFromLayers = (layers, leafHash) => {
|
|
34
|
+
const proof = [];
|
|
35
|
+
let hash = leafHash;
|
|
36
|
+
for (let layerNum = 0; layerNum < layers.length - 1; layerNum++) {
|
|
37
|
+
const layer = at(layers, layerNum);
|
|
38
|
+
const index = layer.indexOf(hash);
|
|
39
|
+
if (index === -1) throw new Error("merkle: leaf hash not present in layer");
|
|
40
|
+
let partnerIndex = index % 2 === 1 ? index - 1 : index + 1;
|
|
41
|
+
if (partnerIndex > layer.length - 1) partnerIndex = index;
|
|
42
|
+
const partner = at(layer, partnerIndex);
|
|
43
|
+
const pair = partnerIndex > index ? [hash, partner] : [partner, hash];
|
|
44
|
+
proof.push(pair);
|
|
45
|
+
hash = hashMerklePair(pair[0], pair[1]);
|
|
46
|
+
}
|
|
47
|
+
return [...proof, [merkleRootFromLayers(layers)]];
|
|
52
48
|
};
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return hash === root;
|
|
75
|
-
} catch {
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
49
|
+
/** Verify a leaf + sibling path recomputes to the proof's embedded root. */
|
|
50
|
+
var verifyMerkleProof = (leafHash, proof) => {
|
|
51
|
+
try {
|
|
52
|
+
const firstLayer = proof[0];
|
|
53
|
+
if (firstLayer === void 0 || firstLayer.indexOf(leafHash) === -1) return false;
|
|
54
|
+
if (proof.length === 1) return at(firstLayer, 0) === leafHash;
|
|
55
|
+
const root = at(at(proof, proof.length - 1), 0);
|
|
56
|
+
let hash = leafHash;
|
|
57
|
+
for (let i = 0; i < proof.length - 1; i++) {
|
|
58
|
+
const layer = at(proof, i);
|
|
59
|
+
if (layer.indexOf(hash) === -1) return false;
|
|
60
|
+
hash = hashMerklePair(at(layer, 0), at(layer, 1));
|
|
61
|
+
if (at(proof, i + 1).indexOf(hash) === -1) return false;
|
|
62
|
+
}
|
|
63
|
+
return hash === root;
|
|
64
|
+
} catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
78
67
|
};
|
|
68
|
+
//#endregion
|
|
79
69
|
exports.buildMerkleLayers = buildMerkleLayers;
|
|
80
70
|
exports.hashMerklePair = hashMerklePair;
|
|
81
71
|
exports.merkleProofFromLayers = merkleProofFromLayers;
|
package/dist/cjs/proof.cjs
CHANGED
|
@@ -1,81 +1,99 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
const require_merkle = require("./merkle.cjs");
|
|
2
|
+
let _prosopo_util_crypto = require("@prosopo/util-crypto");
|
|
3
|
+
//#region src/proof.ts
|
|
4
|
+
var FINGERPRINT_PROOF_VERSION = 1;
|
|
5
|
+
/**
|
|
6
|
+
* The fixed set of components the client discloses in a proof of fingerprint.
|
|
7
|
+
* Disclosing every component (the previous default) made the proof enormous —
|
|
8
|
+
* each disclosure carries a full Merkle path and its raw value, and components
|
|
9
|
+
* like webgl/audio/fonts have very large values. Selective disclosure keeps the
|
|
10
|
+
* commitment (`root`) over the whole component set while only these cheap,
|
|
11
|
+
* stable scalar components carry a path + value, shrinking the payload ~10x.
|
|
12
|
+
*
|
|
13
|
+
* The provider-side validator's bounds MUST be a subset of these keys: a bounded
|
|
14
|
+
* key that isn't disclosed would always fail validation as `missing:<key>`.
|
|
15
|
+
*/
|
|
16
|
+
var FINGERPRINT_DISCLOSURE_KEYS = [
|
|
17
|
+
"colorDepth",
|
|
18
|
+
"cookiesEnabled",
|
|
19
|
+
"sessionStorage",
|
|
20
|
+
"localStorage",
|
|
21
|
+
"timezone",
|
|
22
|
+
"hardwareConcurrency",
|
|
23
|
+
"languages",
|
|
24
|
+
"architecture"
|
|
15
25
|
];
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
var escapeKey = (key) => key.replace(/([:|\\])/g, "\\$1");
|
|
27
|
+
var componentLeafContent = (key, component) => {
|
|
28
|
+
const serialized = "error" in component ? "error" : JSON.stringify(component.value);
|
|
29
|
+
return `${escapeKey(key)}:${serialized}`;
|
|
20
30
|
};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
var disclosureLeafContent = (disclosure) => {
|
|
32
|
+
const serialized = disclosure.error ? "error" : JSON.stringify(disclosure.value);
|
|
33
|
+
return `${escapeKey(disclosure.key)}:${serialized}`;
|
|
24
34
|
};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
35
|
+
var leafHashForContent = (content) => (0, _prosopo_util_crypto.hexHash)(content);
|
|
36
|
+
/**
|
|
37
|
+
* Build a {@link FingerprintProof} from an already-resolved FingerprintJS
|
|
38
|
+
* components map. The commitment always covers every component (in sorted key
|
|
39
|
+
* order); `discloseKeys` selects which components are revealed (defaulting to
|
|
40
|
+
* all). Keys that are not present in the fingerprint are skipped — a validator
|
|
41
|
+
* should treat an expected-but-absent disclosure as a failure.
|
|
42
|
+
*/
|
|
43
|
+
var buildFingerprintProofFromComponents = (components, discloseKeys) => {
|
|
44
|
+
const keys = Object.keys(components).sort();
|
|
45
|
+
if (keys.length === 0) throw new Error("fingerprint proof: no components to commit to");
|
|
46
|
+
const leafHashes = keys.map((key) => {
|
|
47
|
+
const component = components[key];
|
|
48
|
+
if (component === void 0) throw new Error(`fingerprint proof: missing component ${key}`);
|
|
49
|
+
return leafHashForContent(componentLeafContent(key, component));
|
|
50
|
+
});
|
|
51
|
+
const layers = require_merkle.buildMerkleLayers(leafHashes);
|
|
52
|
+
const root = require_merkle.merkleRootFromLayers(layers);
|
|
53
|
+
const disclose = discloseKeys ?? keys;
|
|
54
|
+
const disclosures = [];
|
|
55
|
+
for (const key of disclose) {
|
|
56
|
+
const index = keys.indexOf(key);
|
|
57
|
+
if (index === -1) continue;
|
|
58
|
+
const component = components[key];
|
|
59
|
+
const leafHash = leafHashes[index];
|
|
60
|
+
if (component === void 0 || leafHash === void 0) continue;
|
|
61
|
+
const proof = require_merkle.merkleProofFromLayers(layers, leafHash);
|
|
62
|
+
disclosures.push("error" in component ? {
|
|
63
|
+
key,
|
|
64
|
+
error: true,
|
|
65
|
+
proof
|
|
66
|
+
} : {
|
|
67
|
+
key,
|
|
68
|
+
value: component.value,
|
|
69
|
+
proof
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
v: 1,
|
|
74
|
+
root,
|
|
75
|
+
disclosures
|
|
76
|
+
};
|
|
58
77
|
};
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
return true;
|
|
78
|
+
/**
|
|
79
|
+
* Structural verification of a proof: every disclosed `(key, value)` re-hashes
|
|
80
|
+
* to a leaf that is proven to belong to the single committed `root`. This is
|
|
81
|
+
* the non-secret half of validation — the value-bounding rules live in the
|
|
82
|
+
* provider-side (closed-source) validator and are layered on top of this.
|
|
83
|
+
*/
|
|
84
|
+
var verifyFingerprintProofStructure = (proof) => {
|
|
85
|
+
if (proof.v !== 1) return false;
|
|
86
|
+
if (typeof proof.root !== "string" || proof.disclosures.length === 0) return false;
|
|
87
|
+
for (const disclosure of proof.disclosures) {
|
|
88
|
+
const leafHash = leafHashForContent(disclosureLeafContent(disclosure));
|
|
89
|
+
if (!require_merkle.verifyMerkleProof(leafHash, disclosure.proof)) return false;
|
|
90
|
+
const rootLayer = disclosure.proof[disclosure.proof.length - 1];
|
|
91
|
+
if (rootLayer === void 0 || rootLayer[0] !== proof.root) return false;
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
77
94
|
};
|
|
78
|
-
|
|
95
|
+
var encodeFingerprintProof = (proof) => JSON.stringify(proof);
|
|
96
|
+
//#endregion
|
|
79
97
|
exports.FINGERPRINT_DISCLOSURE_KEYS = FINGERPRINT_DISCLOSURE_KEYS;
|
|
80
98
|
exports.FINGERPRINT_PROOF_VERSION = FINGERPRINT_PROOF_VERSION;
|
|
81
99
|
exports.buildFingerprintProofFromComponents = buildFingerprintProofFromComponents;
|