@keynv/core 0.1.0-rc.23
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/LICENSE +21 -0
- package/dist/audit/chain.d.ts +44 -0
- package/dist/audit/chain.d.ts.map +1 -0
- package/dist/audit/chain.js +134 -0
- package/dist/audit/chain.js.map +1 -0
- package/dist/audit/chain.test.d.ts +2 -0
- package/dist/audit/chain.test.d.ts.map +1 -0
- package/dist/audit/chain.test.js +192 -0
- package/dist/audit/chain.test.js.map +1 -0
- package/dist/audit/index.d.ts +5 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +4 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/payload-schemas.d.ts +343 -0
- package/dist/audit/payload-schemas.d.ts.map +1 -0
- package/dist/audit/payload-schemas.js +112 -0
- package/dist/audit/payload-schemas.js.map +1 -0
- package/dist/audit/payload-schemas.test.d.ts +2 -0
- package/dist/audit/payload-schemas.test.d.ts.map +1 -0
- package/dist/audit/payload-schemas.test.js +93 -0
- package/dist/audit/payload-schemas.test.js.map +1 -0
- package/dist/audit/types.d.ts +34 -0
- package/dist/audit/types.d.ts.map +1 -0
- package/dist/audit/types.js +6 -0
- package/dist/audit/types.js.map +1 -0
- package/dist/crypto/envelope.d.ts +55 -0
- package/dist/crypto/envelope.d.ts.map +1 -0
- package/dist/crypto/envelope.js +108 -0
- package/dist/crypto/envelope.js.map +1 -0
- package/dist/crypto/envelope.test.d.ts +2 -0
- package/dist/crypto/envelope.test.d.ts.map +1 -0
- package/dist/crypto/envelope.test.js +163 -0
- package/dist/crypto/envelope.test.js.map +1 -0
- package/dist/crypto/index.d.ts +5 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +4 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/sodium.d.ts +21 -0
- package/dist/crypto/sodium.d.ts.map +1 -0
- package/dist/crypto/sodium.js +43 -0
- package/dist/crypto/sodium.js.map +1 -0
- package/dist/crypto/types.d.ts +37 -0
- package/dist/crypto/types.d.ts.map +1 -0
- package/dist/crypto/types.js +11 -0
- package/dist/crypto/types.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/reference/index.d.ts +4 -0
- package/dist/reference/index.d.ts.map +1 -0
- package/dist/reference/index.js +3 -0
- package/dist/reference/index.js.map +1 -0
- package/dist/reference/parser-property.test.d.ts +2 -0
- package/dist/reference/parser-property.test.d.ts.map +1 -0
- package/dist/reference/parser-property.test.js +115 -0
- package/dist/reference/parser-property.test.js.map +1 -0
- package/dist/reference/parser.d.ts +54 -0
- package/dist/reference/parser.d.ts.map +1 -0
- package/dist/reference/parser.js +144 -0
- package/dist/reference/parser.js.map +1 -0
- package/dist/reference/parser.test.d.ts +2 -0
- package/dist/reference/parser.test.d.ts.map +1 -0
- package/dist/reference/parser.test.js +195 -0
- package/dist/reference/parser.test.js.map +1 -0
- package/dist/reference/types.d.ts +52 -0
- package/dist/reference/types.d.ts.map +1 -0
- package/dist/reference/types.js +11 -0
- package/dist/reference/types.js.map +1 -0
- package/dist/validation/index.d.ts +33 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +45 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/schemas.test.d.ts +2 -0
- package/dist/validation/schemas.test.d.ts.map +1 -0
- package/dist/validation/schemas.test.js +18 -0
- package/dist/validation/schemas.test.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 keynv-labs and contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type AuditEntry, type AuditInput } from './types.js';
|
|
2
|
+
export declare function configureChainKey(key: Uint8Array | null): void;
|
|
3
|
+
/** True once a tamper-evident chain key has been configured. */
|
|
4
|
+
export declare function isChainKeyConfigured(): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Computes the hash for a NEW audit entry. When a chain key is configured
|
|
7
|
+
* (via configureChainKey) this is an HMAC-SHA-256 tagged with the `v1:`
|
|
8
|
+
* prefix; otherwise it is a plain SHA-256 (not tamper-evident, legacy/test
|
|
9
|
+
* only).
|
|
10
|
+
*/
|
|
11
|
+
export declare function computeHash(prevHash: string, input: AuditInput): string;
|
|
12
|
+
/**
|
|
13
|
+
* Builds the next chain entry. The caller persists the returned object
|
|
14
|
+
* verbatim (id is the auto-incremented row id from the DB).
|
|
15
|
+
*
|
|
16
|
+
* Pass `null` as `prev` when appending the very first entry.
|
|
17
|
+
*/
|
|
18
|
+
export declare function appendEntry(prev: AuditEntry | null, input: AuditInput, id: number): AuditEntry;
|
|
19
|
+
export interface VerifyResult {
|
|
20
|
+
readonly ok: boolean;
|
|
21
|
+
/** Index (0-based, into `entries`) of the first inconsistent row. */
|
|
22
|
+
readonly brokenAt?: number;
|
|
23
|
+
readonly reason?: 'prev_hash_mismatch' | 'hash_mismatch';
|
|
24
|
+
}
|
|
25
|
+
export interface VerifyOptions {
|
|
26
|
+
/**
|
|
27
|
+
* The expected `prev_hash` of the first entry in `entries`. Defaults
|
|
28
|
+
* to GENESIS_HASH (the start of the chain). Set to the tail hash of
|
|
29
|
+
* the previous page when verifying a paginated chain so the cross-
|
|
30
|
+
* page boundary is checked. Without this, verifying any chain of
|
|
31
|
+
* more than one page produces a false `prev_hash_mismatch`.
|
|
32
|
+
*/
|
|
33
|
+
readonly startingPrevHash?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Walks an audit chain and reports the first inconsistency, if any.
|
|
37
|
+
*
|
|
38
|
+
* Verifies two invariants per row:
|
|
39
|
+
* 1. row.prev_hash equals the predecessor's hash (or
|
|
40
|
+
* `opts.startingPrevHash` / GENESIS_HASH for the first row).
|
|
41
|
+
* 2. row.hash equals the recomputed hash over (prev_hash, inputs).
|
|
42
|
+
*/
|
|
43
|
+
export declare function verifyChain(entries: readonly AuditEntry[], opts?: VerifyOptions): VerifyResult;
|
|
44
|
+
//# sourceMappingURL=chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../../src/audit/chain.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAgB,MAAM,YAAY,CAAC;AAwB5E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAE9D;AAED,gEAAgE;AAChE,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAgCD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CAMvE;AAoBD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,CAa9F;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,GAAG,eAAe,CAAC;CAC1D;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,IAAI,GAAE,aAAkB,GACvB,YAAY,CAcd"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { createHash, createHmac } from 'node:crypto';
|
|
2
|
+
import { GENESIS_HASH } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* HMAC key that makes the chain tamper-evident: an attacker with DB write
|
|
5
|
+
* access cannot recompute hashes without it. The server configures it from
|
|
6
|
+
* the KEK at startup (see configureChainKey). When no key is set, hashing
|
|
7
|
+
* uses a plain SHA-256 that is NOT tamper-evident — used only by tests.
|
|
8
|
+
*
|
|
9
|
+
* Keyed hashes carry a `v1:` prefix. Verification is STRICT and symmetric to
|
|
10
|
+
* the current configuration to defeat downgrade attacks: when a key IS
|
|
11
|
+
* configured every row must be a keyed (`v1:`) HMAC (a bare hash is rejected
|
|
12
|
+
* as a downgrade); when NO key is configured every row must be a bare keyless
|
|
13
|
+
* hash. There is intentionally no keyless fallback while a key is present, so
|
|
14
|
+
* an attacker cannot strip the prefix and recompute keyless to forge a row.
|
|
15
|
+
*
|
|
16
|
+
* Migration note: turning the key on establishes tamper-evidence for rows
|
|
17
|
+
* written from then on. A chain that contains rows written by an older
|
|
18
|
+
* keyless build will not HMAC-verify under a configured key — those rows are
|
|
19
|
+
* retained but reported as not verifiable.
|
|
20
|
+
*/
|
|
21
|
+
let chainHmacKey = null;
|
|
22
|
+
const HMAC_PREFIX = 'v1:';
|
|
23
|
+
export function configureChainKey(key) {
|
|
24
|
+
chainHmacKey = key;
|
|
25
|
+
}
|
|
26
|
+
/** True once a tamper-evident chain key has been configured. */
|
|
27
|
+
export function isChainKeyConfigured() {
|
|
28
|
+
return chainHmacKey !== null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* JSON-canonicalize a payload so the hash is reproducible regardless of
|
|
32
|
+
* key insertion order. Sorts object keys at every level; arrays keep
|
|
33
|
+
* their original order. Undefined values are normalised to null to
|
|
34
|
+
* avoid JSON.stringify inconsistencies.
|
|
35
|
+
*/
|
|
36
|
+
function canonicalize(value) {
|
|
37
|
+
if (value === null || typeof value !== 'object') {
|
|
38
|
+
return value === undefined ? 'null' : JSON.stringify(value);
|
|
39
|
+
}
|
|
40
|
+
if (Array.isArray(value)) {
|
|
41
|
+
return `[${value.map(canonicalize).join(',')}]`;
|
|
42
|
+
}
|
|
43
|
+
const obj = value;
|
|
44
|
+
const keys = Object.keys(obj).sort();
|
|
45
|
+
const parts = keys.map((k) => `${JSON.stringify(k)}:${canonicalize(obj[k])}`);
|
|
46
|
+
return `{${parts.join(',')}}`;
|
|
47
|
+
}
|
|
48
|
+
function canonicalOf(prevHash, input) {
|
|
49
|
+
return canonicalize({
|
|
50
|
+
prev_hash: prevHash,
|
|
51
|
+
ts: input.ts,
|
|
52
|
+
actor_user_id: input.actor_user_id,
|
|
53
|
+
actor_agent: input.actor_agent,
|
|
54
|
+
event_type: input.event_type,
|
|
55
|
+
payload: input.payload,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Computes the hash for a NEW audit entry. When a chain key is configured
|
|
60
|
+
* (via configureChainKey) this is an HMAC-SHA-256 tagged with the `v1:`
|
|
61
|
+
* prefix; otherwise it is a plain SHA-256 (not tamper-evident, legacy/test
|
|
62
|
+
* only).
|
|
63
|
+
*/
|
|
64
|
+
export function computeHash(prevHash, input) {
|
|
65
|
+
const canonical = canonicalOf(prevHash, input);
|
|
66
|
+
if (chainHmacKey) {
|
|
67
|
+
return HMAC_PREFIX + createHmac('sha256', chainHmacKey).update(canonical, 'utf8').digest('hex');
|
|
68
|
+
}
|
|
69
|
+
return createHash('sha256').update(canonical, 'utf8').digest('hex');
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Recomputes a stored hash and reports whether it matches, STRICTLY in the
|
|
73
|
+
* current key mode so a downgrade is impossible:
|
|
74
|
+
* - key configured → the row MUST be a `v1:` HMAC; a bare hash is rejected.
|
|
75
|
+
* - no key configured → the row MUST be a bare keyless SHA-256; a `v1:` row
|
|
76
|
+
* cannot be verified without the key and is rejected.
|
|
77
|
+
*/
|
|
78
|
+
function hashMatches(prevHash, input, storedHash) {
|
|
79
|
+
const canonical = canonicalOf(prevHash, input);
|
|
80
|
+
if (chainHmacKey) {
|
|
81
|
+
if (!storedHash.startsWith(HMAC_PREFIX))
|
|
82
|
+
return false; // downgrade attempt
|
|
83
|
+
const h = `${HMAC_PREFIX}${createHmac('sha256', chainHmacKey).update(canonical, 'utf8').digest('hex')}`;
|
|
84
|
+
return h === storedHash;
|
|
85
|
+
}
|
|
86
|
+
if (storedHash.startsWith(HMAC_PREFIX))
|
|
87
|
+
return false; // keyed row, no key to verify
|
|
88
|
+
return createHash('sha256').update(canonical, 'utf8').digest('hex') === storedHash;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Builds the next chain entry. The caller persists the returned object
|
|
92
|
+
* verbatim (id is the auto-incremented row id from the DB).
|
|
93
|
+
*
|
|
94
|
+
* Pass `null` as `prev` when appending the very first entry.
|
|
95
|
+
*/
|
|
96
|
+
export function appendEntry(prev, input, id) {
|
|
97
|
+
const prevHash = prev?.hash ?? GENESIS_HASH;
|
|
98
|
+
const hash = computeHash(prevHash, input);
|
|
99
|
+
return {
|
|
100
|
+
id,
|
|
101
|
+
prev_hash: prevHash,
|
|
102
|
+
hash,
|
|
103
|
+
ts: input.ts,
|
|
104
|
+
actor_user_id: input.actor_user_id,
|
|
105
|
+
actor_agent: input.actor_agent,
|
|
106
|
+
event_type: input.event_type,
|
|
107
|
+
payload: input.payload,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Walks an audit chain and reports the first inconsistency, if any.
|
|
112
|
+
*
|
|
113
|
+
* Verifies two invariants per row:
|
|
114
|
+
* 1. row.prev_hash equals the predecessor's hash (or
|
|
115
|
+
* `opts.startingPrevHash` / GENESIS_HASH for the first row).
|
|
116
|
+
* 2. row.hash equals the recomputed hash over (prev_hash, inputs).
|
|
117
|
+
*/
|
|
118
|
+
export function verifyChain(entries, opts = {}) {
|
|
119
|
+
const expectedFirstPrevHash = opts.startingPrevHash ?? GENESIS_HASH;
|
|
120
|
+
for (let i = 0; i < entries.length; i++) {
|
|
121
|
+
const cur = entries[i];
|
|
122
|
+
if (!cur)
|
|
123
|
+
continue;
|
|
124
|
+
const expectedPrevHash = i === 0 ? expectedFirstPrevHash : entries[i - 1]?.hash;
|
|
125
|
+
if (cur.prev_hash !== expectedPrevHash) {
|
|
126
|
+
return { ok: false, brokenAt: i, reason: 'prev_hash_mismatch' };
|
|
127
|
+
}
|
|
128
|
+
if (!hashMatches(cur.prev_hash, cur, cur.hash)) {
|
|
129
|
+
return { ok: false, brokenAt: i, reason: 'hash_mismatch' };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return { ok: true };
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../../src/audit/chain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.test.d.ts","sourceRoot":"","sources":["../../src/audit/chain.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { GENESIS_HASH, appendEntry, computeHash, configureChainKey, isChainKeyConfigured, verifyChain, } from './index.js';
|
|
3
|
+
function input(seed) {
|
|
4
|
+
return {
|
|
5
|
+
ts: `2026-05-09T12:00:${String(seed).padStart(2, '0')}.000Z`,
|
|
6
|
+
actor_user_id: 'u_alice',
|
|
7
|
+
actor_agent: 'cli-0.0.0',
|
|
8
|
+
event_type: 'secret.read.allowed',
|
|
9
|
+
payload: { alias: `@p.dev.k${seed}`, version: 1 },
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function buildChain(n) {
|
|
13
|
+
const entries = [];
|
|
14
|
+
let prev = null;
|
|
15
|
+
for (let i = 0; i < n; i++) {
|
|
16
|
+
const e = appendEntry(prev, input(i), i + 1);
|
|
17
|
+
entries.push(e);
|
|
18
|
+
prev = e;
|
|
19
|
+
}
|
|
20
|
+
return entries;
|
|
21
|
+
}
|
|
22
|
+
describe('computeHash', () => {
|
|
23
|
+
it('is deterministic for equal inputs', () => {
|
|
24
|
+
const a = computeHash(GENESIS_HASH, input(1));
|
|
25
|
+
const b = computeHash(GENESIS_HASH, input(1));
|
|
26
|
+
expect(a).toBe(b);
|
|
27
|
+
});
|
|
28
|
+
it('changes when prev_hash changes', () => {
|
|
29
|
+
const a = computeHash(GENESIS_HASH, input(1));
|
|
30
|
+
const b = computeHash(`${'1'.repeat(64)}`, input(1));
|
|
31
|
+
expect(a).not.toBe(b);
|
|
32
|
+
});
|
|
33
|
+
it('is independent of payload key insertion order', () => {
|
|
34
|
+
const i = {
|
|
35
|
+
ts: '2026-05-09T12:00:00.000Z',
|
|
36
|
+
actor_user_id: 'u',
|
|
37
|
+
actor_agent: 'cli',
|
|
38
|
+
event_type: 'secret.read.allowed',
|
|
39
|
+
payload: { alias: '@p.d.k', version: 1, extra: { a: 1, b: 2 } },
|
|
40
|
+
};
|
|
41
|
+
const j = {
|
|
42
|
+
...i,
|
|
43
|
+
payload: { extra: { b: 2, a: 1 }, version: 1, alias: '@p.d.k' },
|
|
44
|
+
};
|
|
45
|
+
expect(computeHash(GENESIS_HASH, i)).toBe(computeHash(GENESIS_HASH, j));
|
|
46
|
+
});
|
|
47
|
+
it('is 64 hex chars (SHA-256)', () => {
|
|
48
|
+
expect(computeHash(GENESIS_HASH, input(1))).toMatch(/^[0-9a-f]{64}$/);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('appendEntry', () => {
|
|
52
|
+
it('uses GENESIS_HASH for the first entry', () => {
|
|
53
|
+
const e = appendEntry(null, input(1), 1);
|
|
54
|
+
expect(e.prev_hash).toBe(GENESIS_HASH);
|
|
55
|
+
expect(e.hash).toMatch(/^[0-9a-f]{64}$/);
|
|
56
|
+
});
|
|
57
|
+
it('chains subsequent entries to the previous hash', () => {
|
|
58
|
+
const a = appendEntry(null, input(1), 1);
|
|
59
|
+
const b = appendEntry(a, input(2), 2);
|
|
60
|
+
expect(b.prev_hash).toBe(a.hash);
|
|
61
|
+
});
|
|
62
|
+
it('returns identical entries for the same input + prev', () => {
|
|
63
|
+
const a1 = appendEntry(null, input(1), 1);
|
|
64
|
+
const a2 = appendEntry(null, input(1), 1);
|
|
65
|
+
expect(a1.hash).toBe(a2.hash);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe('verifyChain', () => {
|
|
69
|
+
it('returns ok for a valid chain', () => {
|
|
70
|
+
const chain = buildChain(50);
|
|
71
|
+
expect(verifyChain(chain)).toEqual({ ok: true });
|
|
72
|
+
});
|
|
73
|
+
it('returns ok for an empty chain', () => {
|
|
74
|
+
expect(verifyChain([])).toEqual({ ok: true });
|
|
75
|
+
});
|
|
76
|
+
it('detects a flipped payload byte (hash mismatch)', () => {
|
|
77
|
+
const chain = buildChain(10);
|
|
78
|
+
const tampered = chain.map((e, i) => i === 5 ? { ...e, payload: { ...e.payload, version: 999 } } : e);
|
|
79
|
+
const result = verifyChain(tampered);
|
|
80
|
+
expect(result.ok).toBe(false);
|
|
81
|
+
expect(result.brokenAt).toBe(5);
|
|
82
|
+
expect(result.reason).toBe('hash_mismatch');
|
|
83
|
+
});
|
|
84
|
+
it('detects a removed entry (prev_hash mismatch on the row that follows)', () => {
|
|
85
|
+
const chain = buildChain(10);
|
|
86
|
+
const truncated = [...chain.slice(0, 5), ...chain.slice(6)];
|
|
87
|
+
const result = verifyChain(truncated);
|
|
88
|
+
expect(result.ok).toBe(false);
|
|
89
|
+
expect(result.brokenAt).toBe(5);
|
|
90
|
+
expect(result.reason).toBe('prev_hash_mismatch');
|
|
91
|
+
});
|
|
92
|
+
it('detects a re-ordered entry', () => {
|
|
93
|
+
const chain = buildChain(10);
|
|
94
|
+
const swapped = [...chain.slice(0, 3), chain[4], chain[3], ...chain.slice(5)];
|
|
95
|
+
const result = verifyChain(swapped);
|
|
96
|
+
expect(result.ok).toBe(false);
|
|
97
|
+
expect(result.brokenAt).toBeGreaterThanOrEqual(3);
|
|
98
|
+
});
|
|
99
|
+
it('detects a forged entry inserted in the middle', () => {
|
|
100
|
+
const chain = buildChain(10);
|
|
101
|
+
const forged = {
|
|
102
|
+
id: 999,
|
|
103
|
+
prev_hash: chain[4].hash,
|
|
104
|
+
hash: '0'.repeat(64),
|
|
105
|
+
...input(99),
|
|
106
|
+
};
|
|
107
|
+
const tampered = [...chain.slice(0, 5), forged, ...chain.slice(5)];
|
|
108
|
+
const result = verifyChain(tampered);
|
|
109
|
+
expect(result.ok).toBe(false);
|
|
110
|
+
expect(result.brokenAt).toBe(5);
|
|
111
|
+
});
|
|
112
|
+
it('handles a 1000-entry chain without false positives', () => {
|
|
113
|
+
const chain = buildChain(1000);
|
|
114
|
+
expect(verifyChain(chain)).toEqual({ ok: true });
|
|
115
|
+
});
|
|
116
|
+
it('verifies across page boundaries when startingPrevHash is threaded (regression for audit B1)', () => {
|
|
117
|
+
const chain = buildChain(2500);
|
|
118
|
+
const page1 = chain.slice(0, 1000);
|
|
119
|
+
const page2 = chain.slice(1000, 2000);
|
|
120
|
+
const page3 = chain.slice(2000);
|
|
121
|
+
expect(verifyChain(page1)).toEqual({ ok: true });
|
|
122
|
+
// Without startingPrevHash the second page falsely reports a
|
|
123
|
+
// mismatch — exactly the bug audit B1 caught.
|
|
124
|
+
expect(verifyChain(page2)).toMatchObject({ ok: false, reason: 'prev_hash_mismatch' });
|
|
125
|
+
// With startingPrevHash threaded, every page boundary checks out.
|
|
126
|
+
const tail1 = page1.at(-1);
|
|
127
|
+
const tail2 = page2.at(-1);
|
|
128
|
+
if (!tail1 || !tail2)
|
|
129
|
+
throw new Error('expected non-empty pages');
|
|
130
|
+
expect(verifyChain(page2, { startingPrevHash: tail1.hash })).toEqual({ ok: true });
|
|
131
|
+
expect(verifyChain(page3, { startingPrevHash: tail2.hash })).toEqual({ ok: true });
|
|
132
|
+
});
|
|
133
|
+
it('flags a tampered cross-page boundary', () => {
|
|
134
|
+
const chain = buildChain(2000);
|
|
135
|
+
const page1 = chain.slice(0, 1000);
|
|
136
|
+
const tail1 = page1.at(-1);
|
|
137
|
+
if (!tail1)
|
|
138
|
+
throw new Error('expected page1 non-empty');
|
|
139
|
+
const tamperedPage2 = chain
|
|
140
|
+
.slice(1000)
|
|
141
|
+
.map((e, i) => (i === 0 ? { ...e, prev_hash: 'a'.repeat(64) } : e));
|
|
142
|
+
const result = verifyChain(tamperedPage2, { startingPrevHash: tail1.hash });
|
|
143
|
+
expect(result.ok).toBe(false);
|
|
144
|
+
expect(result.brokenAt).toBe(0);
|
|
145
|
+
expect(result.reason).toBe('prev_hash_mismatch');
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe('tamper-evident (HMAC) chain key', () => {
|
|
149
|
+
const KEY = new Uint8Array(32).fill(7);
|
|
150
|
+
afterEach(() => configureChainKey(null)); // reset module-global between tests
|
|
151
|
+
it('tags keyed hashes with the v1: prefix and verifies them', () => {
|
|
152
|
+
configureChainKey(KEY);
|
|
153
|
+
expect(isChainKeyConfigured()).toBe(true);
|
|
154
|
+
const chain = buildChain(20);
|
|
155
|
+
expect(chain[0]?.hash.startsWith('v1:')).toBe(true);
|
|
156
|
+
expect(verifyChain(chain)).toEqual({ ok: true });
|
|
157
|
+
});
|
|
158
|
+
it('cannot be re-forged by recomputing keyless after a payload edit', () => {
|
|
159
|
+
configureChainKey(KEY);
|
|
160
|
+
const chain = buildChain(10);
|
|
161
|
+
// Attacker (no key) edits a payload and recomputes the hash keyless.
|
|
162
|
+
configureChainKey(null);
|
|
163
|
+
const forgedHash = computeHash(chain[5].prev_hash, {
|
|
164
|
+
...input(5),
|
|
165
|
+
payload: { alias: '@p.dev.k5', version: 999 },
|
|
166
|
+
});
|
|
167
|
+
const tampered = chain.map((e, i) => i === 5 ? { ...e, payload: { alias: '@p.dev.k5', version: 999 }, hash: forgedHash } : e);
|
|
168
|
+
// Verifier (with the key) rejects it: the row is a v1: row, so a keyless
|
|
169
|
+
// recompute can never match.
|
|
170
|
+
configureChainKey(KEY);
|
|
171
|
+
const result = verifyChain(tampered);
|
|
172
|
+
expect(result.ok).toBe(false);
|
|
173
|
+
expect(result.reason).toBe('hash_mismatch');
|
|
174
|
+
expect(result.brokenAt).toBe(5);
|
|
175
|
+
});
|
|
176
|
+
it('reports a keyed chain as broken when the key is absent at verify time', () => {
|
|
177
|
+
configureChainKey(KEY);
|
|
178
|
+
const chain = buildChain(5);
|
|
179
|
+
configureChainKey(null);
|
|
180
|
+
expect(verifyChain(chain).ok).toBe(false);
|
|
181
|
+
});
|
|
182
|
+
it('rejects an entirely keyless chain when a key is configured (full-downgrade protection)', () => {
|
|
183
|
+
// An attacker who rewrites every row as keyless must NOT pass verification
|
|
184
|
+
// once the verifier holds the key.
|
|
185
|
+
configureChainKey(null);
|
|
186
|
+
const keyless = buildChain(5); // all bare SHA-256
|
|
187
|
+
expect(keyless[0]?.hash.startsWith('v1:')).toBe(false);
|
|
188
|
+
configureChainKey(KEY);
|
|
189
|
+
expect(verifyChain(keyless).ok).toBe(false);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
//# sourceMappingURL=chain.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.test.js","sourceRoot":"","sources":["../../src/audit/chain.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { AuditEntry, AuditEventType, AuditInput } from './types.js';
|
|
2
|
+
export { GENESIS_HASH } from './types.js';
|
|
3
|
+
export { appendEntry, computeHash, configureChainKey, isChainKeyConfigured, verifyChain, type VerifyOptions, type VerifyResult, } from './chain.js';
|
|
4
|
+
export { PAYLOAD_SCHEMAS, validateAuditPayload } from './payload-schemas.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EACL,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EACL,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,WAAW,GAGZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
|