@zanii/monitor 0.1.0 → 0.2.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/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -8
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +24 -10
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEjF,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,qEAAqE;IACrE,KAAK,EAAE,YAAY,CAAC;CACrB;AAQD;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,YAAY,EACnB,SAAS,GAAE,SAAiC,GAC3C,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEjF,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,qEAAqE;IACrE,KAAK,EAAE,YAAY,CAAC;CACrB;AAQD;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,YAAY,EACnB,SAAS,GAAE,SAAiC,GAC3C,OAAO,CAAC,aAAa,CAAC,CAkExB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1D;AAED,8EAA8E;AAC9E,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,KAAK,CAAC,CAevF"}
|
package/dist/index.js
CHANGED
|
@@ -31,12 +31,25 @@ export async function checkOnce(server, prev, fetchImpl = (u, i) => fetch(u, i))
|
|
|
31
31
|
const checks = [];
|
|
32
32
|
const violations = [];
|
|
33
33
|
const push = (name, ok, detail) => {
|
|
34
|
-
checks.push({ name, ok, detail });
|
|
34
|
+
checks.push(ok ? { name, ok } : { name, ok, detail });
|
|
35
35
|
if (!ok)
|
|
36
36
|
violations.push(detail ?? name);
|
|
37
37
|
};
|
|
38
38
|
const sth = (await get('/v1/sth'));
|
|
39
39
|
push('signed tree head signature', verifySTH(sth) && !!sth.log_id, 'STH signature invalid');
|
|
40
|
+
// Prove `firstRoot@first` is an append-only prefix of the snapshot head. The proof is
|
|
41
|
+
// PINNED to the snapshot size (SPEC: ?first=m&second=n), so writes landing during the
|
|
42
|
+
// run cannot race the comparison into a false "history rewritten" alarm (TOCTOU).
|
|
43
|
+
// A pre-`second` server ignores the pin and proves against its live tree; we then
|
|
44
|
+
// verify against the (size, root) it actually proved — still catches any rewrite of
|
|
45
|
+
// history up to `first`, at the cost of trusting the served head for the newest tail.
|
|
46
|
+
const verifyExtension = async (first, firstRoot) => {
|
|
47
|
+
if (first === 0)
|
|
48
|
+
return true; // the empty tree is trivially a prefix
|
|
49
|
+
const c = await get(`/v1/consistency?first=${first}&second=${sth.size}`);
|
|
50
|
+
const pinned = c.second === sth.size;
|
|
51
|
+
return verifyConsistency(first, pinned ? sth.size : c.second, toRoot(firstRoot), toRoot(pinned ? sth.root : c.second_root), c.proof.map(hexToBytes));
|
|
52
|
+
};
|
|
40
53
|
if (prev) {
|
|
41
54
|
if (sth.size < prev.size) {
|
|
42
55
|
push(`append-only (size ${sth.size} ≥ ${prev.size})`, false, `log SHRANK: size ${sth.size} < previously seen ${prev.size}`);
|
|
@@ -45,20 +58,24 @@ export async function checkOnce(server, prev, fetchImpl = (u, i) => fetch(u, i))
|
|
|
45
58
|
push('append-only (root unchanged at same size)', sth.root === prev.root, `root changed at unchanged size ${sth.size} — history was rewritten`);
|
|
46
59
|
}
|
|
47
60
|
else {
|
|
48
|
-
|
|
49
|
-
const ok = verifyConsistency(prev.size, sth.size, toRoot(prev.root), toRoot(sth.root), c.proof.map(hexToBytes));
|
|
50
|
-
push(`append-only (consistency ${prev.size}→${sth.size})`, ok, `consistency proof ${prev.size}→${sth.size} FAILED — history was rewritten`);
|
|
61
|
+
push(`append-only (consistency ${prev.size}→${sth.size})`, await verifyExtension(prev.size, prev.root), `consistency proof ${prev.size}→${sth.size} FAILED — history was rewritten`);
|
|
51
62
|
}
|
|
52
63
|
}
|
|
53
64
|
// Every anchored checkpoint must be an append-only prefix of the current tree.
|
|
54
65
|
try {
|
|
55
66
|
const { anchors } = (await get('/v1/anchors'));
|
|
56
67
|
for (const a of anchors ?? []) {
|
|
57
|
-
let ok = verifySTH(a.sth) && a.sth.log_id === sth.log_id
|
|
58
|
-
if (ok && a.sth.size
|
|
59
|
-
|
|
60
|
-
|
|
68
|
+
let ok = verifySTH(a.sth) && a.sth.log_id === sth.log_id;
|
|
69
|
+
if (ok && a.sth.size > sth.size) {
|
|
70
|
+
// anchored after our snapshot — a valid STH this snapshot cannot relate to yet;
|
|
71
|
+
// its extension is checked next run, once the observed head has caught up
|
|
72
|
+
push(`anchor ${short(a.ref)} newer than snapshot (extension checked next run)`, true);
|
|
73
|
+
continue;
|
|
61
74
|
}
|
|
75
|
+
if (ok && a.sth.size === sth.size)
|
|
76
|
+
ok = a.sth.root === sth.root; // same size, different root = equivocation
|
|
77
|
+
if (ok && a.sth.size < sth.size)
|
|
78
|
+
ok = await verifyExtension(a.sth.size, a.sth.root);
|
|
62
79
|
push(`anchor ${short(a.ref)} valid + extended`, ok, `anchor ${short(a.ref)}: invalid STH or current tree is not an append-only extension of it`);
|
|
63
80
|
}
|
|
64
81
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAuB,MAAM,aAAa,CAAC;AA0BhF,MAAM,MAAM,GAAG,CAAC,CAAS,EAAc,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;AAC/E,MAAM,KAAK,GAAG,CAAC,CAAU,EAAU,EAAE;IACnC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1B,OAAO,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,MAAc,EACd,IAAmB,EACnB,YAAuB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;IAE5C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACvC,MAAM,GAAG,GAAG,KAAK,EAAE,CAAS,EAAgB,EAAE;QAC5C,MAAM,CAAC,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAClB,CAAC,CAAC;IAEF,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAW,EAAE,MAAe,EAAE,EAAE;QAC1D,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zanii/monitor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Independent Zanii log monitor: continuously verify the transparency log is append-only (consistency proofs) and that anchored checkpoints hold. Makes 'trust no one' operational.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://ledger.zanii.agency",
|
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@noble/hashes": "^1.7.1",
|
|
33
|
-
"@zanii/core": "0.
|
|
33
|
+
"@zanii/core": "0.4.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^26.1.0",
|
|
37
37
|
"typescript": "^5.8.2",
|
|
38
38
|
"vitest": "^3.0.9",
|
|
39
|
-
"@zanii/testing": "0.1.
|
|
39
|
+
"@zanii/testing": "0.1.1"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsc -p tsconfig.build.json",
|
package/src/index.ts
CHANGED
|
@@ -61,13 +61,27 @@ export async function checkOnce(
|
|
|
61
61
|
const checks: Check[] = [];
|
|
62
62
|
const violations: string[] = [];
|
|
63
63
|
const push = (name: string, ok: boolean, detail?: string) => {
|
|
64
|
-
checks.push({ name, ok, detail });
|
|
64
|
+
checks.push(ok ? { name, ok } : { name, ok, detail });
|
|
65
65
|
if (!ok) violations.push(detail ?? name);
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
const sth = (await get('/v1/sth')) as SignedTreeHead;
|
|
69
69
|
push('signed tree head signature', verifySTH(sth) && !!sth.log_id, 'STH signature invalid');
|
|
70
70
|
|
|
71
|
+
// Prove `firstRoot@first` is an append-only prefix of the snapshot head. The proof is
|
|
72
|
+
// PINNED to the snapshot size (SPEC: ?first=m&second=n), so writes landing during the
|
|
73
|
+
// run cannot race the comparison into a false "history rewritten" alarm (TOCTOU).
|
|
74
|
+
// A pre-`second` server ignores the pin and proves against its live tree; we then
|
|
75
|
+
// verify against the (size, root) it actually proved — still catches any rewrite of
|
|
76
|
+
// history up to `first`, at the cost of trusting the served head for the newest tail.
|
|
77
|
+
const verifyExtension = async (first: number, firstRoot: string): Promise<boolean> => {
|
|
78
|
+
if (first === 0) return true; // the empty tree is trivially a prefix
|
|
79
|
+
const c = await get(`/v1/consistency?first=${first}&second=${sth.size}`);
|
|
80
|
+
const pinned = c.second === sth.size;
|
|
81
|
+
return verifyConsistency(first, pinned ? sth.size : c.second, toRoot(firstRoot),
|
|
82
|
+
toRoot(pinned ? sth.root : c.second_root), (c.proof as string[]).map(hexToBytes));
|
|
83
|
+
};
|
|
84
|
+
|
|
71
85
|
if (prev) {
|
|
72
86
|
if (sth.size < prev.size) {
|
|
73
87
|
push(`append-only (size ${sth.size} ≥ ${prev.size})`, false,
|
|
@@ -76,10 +90,7 @@ export async function checkOnce(
|
|
|
76
90
|
push('append-only (root unchanged at same size)', sth.root === prev.root,
|
|
77
91
|
`root changed at unchanged size ${sth.size} — history was rewritten`);
|
|
78
92
|
} else {
|
|
79
|
-
|
|
80
|
-
const ok = verifyConsistency(prev.size, sth.size, toRoot(prev.root), toRoot(sth.root),
|
|
81
|
-
(c.proof as string[]).map(hexToBytes));
|
|
82
|
-
push(`append-only (consistency ${prev.size}→${sth.size})`, ok,
|
|
93
|
+
push(`append-only (consistency ${prev.size}→${sth.size})`, await verifyExtension(prev.size, prev.root),
|
|
83
94
|
`consistency proof ${prev.size}→${sth.size} FAILED — history was rewritten`);
|
|
84
95
|
}
|
|
85
96
|
}
|
|
@@ -88,12 +99,15 @@ export async function checkOnce(
|
|
|
88
99
|
try {
|
|
89
100
|
const { anchors } = (await get('/v1/anchors')) as { anchors?: Array<{ sth: SignedTreeHead; ref?: unknown }> };
|
|
90
101
|
for (const a of anchors ?? []) {
|
|
91
|
-
let ok = verifySTH(a.sth) && a.sth.log_id === sth.log_id
|
|
92
|
-
if (ok && a.sth.size
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
102
|
+
let ok = verifySTH(a.sth) && a.sth.log_id === sth.log_id;
|
|
103
|
+
if (ok && a.sth.size > sth.size) {
|
|
104
|
+
// anchored after our snapshot — a valid STH this snapshot cannot relate to yet;
|
|
105
|
+
// its extension is checked next run, once the observed head has caught up
|
|
106
|
+
push(`anchor ${short(a.ref)} newer than snapshot (extension checked next run)`, true);
|
|
107
|
+
continue;
|
|
96
108
|
}
|
|
109
|
+
if (ok && a.sth.size === sth.size) ok = a.sth.root === sth.root; // same size, different root = equivocation
|
|
110
|
+
if (ok && a.sth.size < sth.size) ok = await verifyExtension(a.sth.size, a.sth.root);
|
|
97
111
|
push(`anchor ${short(a.ref)} valid + extended`, ok,
|
|
98
112
|
`anchor ${short(a.ref)}: invalid STH or current tree is not an append-only extension of it`);
|
|
99
113
|
}
|