sigild 0.0.1
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/CONTRIBUTING.md +39 -0
- package/LICENSE +202 -0
- package/README.md +70 -0
- package/THREAT_MODEL.md +84 -0
- package/dist/src/audit/index.d.ts +2 -0
- package/dist/src/audit/index.d.ts.map +1 -0
- package/dist/src/audit/index.js +2 -0
- package/dist/src/audit/index.js.map +1 -0
- package/dist/src/audit/log.d.ts +96 -0
- package/dist/src/audit/log.d.ts.map +1 -0
- package/dist/src/audit/log.js +229 -0
- package/dist/src/audit/log.js.map +1 -0
- package/dist/src/bin/sigild.d.ts +3 -0
- package/dist/src/bin/sigild.d.ts.map +1 -0
- package/dist/src/bin/sigild.js +30 -0
- package/dist/src/bin/sigild.js.map +1 -0
- package/dist/src/crypto/aead.d.ts +9 -0
- package/dist/src/crypto/aead.d.ts.map +1 -0
- package/dist/src/crypto/aead.js +38 -0
- package/dist/src/crypto/aead.js.map +1 -0
- package/dist/src/crypto/index.d.ts +5 -0
- package/dist/src/crypto/index.d.ts.map +1 -0
- package/dist/src/crypto/index.js +5 -0
- package/dist/src/crypto/index.js.map +1 -0
- package/dist/src/crypto/kdf.d.ts +10 -0
- package/dist/src/crypto/kdf.d.ts.map +1 -0
- package/dist/src/crypto/kdf.js +27 -0
- package/dist/src/crypto/kdf.js.map +1 -0
- package/dist/src/crypto/keyfile.d.ts +12 -0
- package/dist/src/crypto/keyfile.d.ts.map +1 -0
- package/dist/src/crypto/keyfile.js +114 -0
- package/dist/src/crypto/keyfile.js.map +1 -0
- package/dist/src/crypto/secret-buffer.d.ts +19 -0
- package/dist/src/crypto/secret-buffer.d.ts.map +1 -0
- package/dist/src/crypto/secret-buffer.js +48 -0
- package/dist/src/crypto/secret-buffer.js.map +1 -0
- package/dist/src/daemon/handles.d.ts +51 -0
- package/dist/src/daemon/handles.d.ts.map +1 -0
- package/dist/src/daemon/handles.js +140 -0
- package/dist/src/daemon/handles.js.map +1 -0
- package/dist/src/daemon/index.d.ts +5 -0
- package/dist/src/daemon/index.d.ts.map +1 -0
- package/dist/src/daemon/index.js +5 -0
- package/dist/src/daemon/index.js.map +1 -0
- package/dist/src/daemon/methods.d.ts +20 -0
- package/dist/src/daemon/methods.d.ts.map +1 -0
- package/dist/src/daemon/methods.js +221 -0
- package/dist/src/daemon/methods.js.map +1 -0
- package/dist/src/daemon/passphrase.d.ts +14 -0
- package/dist/src/daemon/passphrase.d.ts.map +1 -0
- package/dist/src/daemon/passphrase.js +49 -0
- package/dist/src/daemon/passphrase.js.map +1 -0
- package/dist/src/daemon/rpc.d.ts +61 -0
- package/dist/src/daemon/rpc.d.ts.map +1 -0
- package/dist/src/daemon/rpc.js +76 -0
- package/dist/src/daemon/rpc.js.map +1 -0
- package/dist/src/daemon/runtime.d.ts +40 -0
- package/dist/src/daemon/runtime.d.ts.map +1 -0
- package/dist/src/daemon/runtime.js +61 -0
- package/dist/src/daemon/runtime.js.map +1 -0
- package/dist/src/daemon/server.d.ts +53 -0
- package/dist/src/daemon/server.d.ts.map +1 -0
- package/dist/src/daemon/server.js +103 -0
- package/dist/src/daemon/server.js.map +1 -0
- package/dist/src/eth/address.d.ts +13 -0
- package/dist/src/eth/address.d.ts.map +1 -0
- package/dist/src/eth/address.js +51 -0
- package/dist/src/eth/address.js.map +1 -0
- package/dist/src/eth/index.d.ts +8 -0
- package/dist/src/eth/index.d.ts.map +1 -0
- package/dist/src/eth/index.js +8 -0
- package/dist/src/eth/index.js.map +1 -0
- package/dist/src/eth/keccak.d.ts +2 -0
- package/dist/src/eth/keccak.d.ts.map +1 -0
- package/dist/src/eth/keccak.js +5 -0
- package/dist/src/eth/keccak.js.map +1 -0
- package/dist/src/eth/rlp.d.ts +16 -0
- package/dist/src/eth/rlp.d.ts.map +1 -0
- package/dist/src/eth/rlp.js +99 -0
- package/dist/src/eth/rlp.js.map +1 -0
- package/dist/src/eth/secp.d.ts +17 -0
- package/dist/src/eth/secp.d.ts.map +1 -0
- package/dist/src/eth/secp.js +43 -0
- package/dist/src/eth/secp.js.map +1 -0
- package/dist/src/eth/sign-message.d.ts +18 -0
- package/dist/src/eth/sign-message.d.ts.map +1 -0
- package/dist/src/eth/sign-message.js +42 -0
- package/dist/src/eth/sign-message.js.map +1 -0
- package/dist/src/eth/sign-tx.d.ts +38 -0
- package/dist/src/eth/sign-tx.d.ts.map +1 -0
- package/dist/src/eth/sign-tx.js +92 -0
- package/dist/src/eth/sign-tx.js.map +1 -0
- package/dist/src/eth/sign-typed.d.ts +33 -0
- package/dist/src/eth/sign-typed.d.ts.map +1 -0
- package/dist/src/eth/sign-typed.js +142 -0
- package/dist/src/eth/sign-typed.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { closeSync, fsyncSync, openSync, readFileSync, writeSync } from 'node:fs';
|
|
2
|
+
import { keccak256 } from '../eth/keccak.js';
|
|
3
|
+
export const ZERO_HASH = '0'.repeat(64);
|
|
4
|
+
export const HASH_HEX_LEN = 64;
|
|
5
|
+
export class AuditChainError extends Error {
|
|
6
|
+
atSeq;
|
|
7
|
+
constructor(msg, atSeq) {
|
|
8
|
+
super(`audit chain error${atSeq !== undefined ? ` at seq=${atSeq}` : ''}: ${msg}`);
|
|
9
|
+
this.name = 'AuditChainError';
|
|
10
|
+
this.atSeq = atSeq;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Canonical JSON serialization: keys sorted lexicographically, recursive.
|
|
15
|
+
* This is what we hash, so it must be deterministic across engine
|
|
16
|
+
* versions and across re-serializations.
|
|
17
|
+
*/
|
|
18
|
+
export function canonicalJSON(value) {
|
|
19
|
+
if (value === null || value === undefined)
|
|
20
|
+
return 'null';
|
|
21
|
+
if (typeof value === 'boolean')
|
|
22
|
+
return value ? 'true' : 'false';
|
|
23
|
+
if (typeof value === 'number') {
|
|
24
|
+
if (!Number.isFinite(value)) {
|
|
25
|
+
throw new Error('canonicalJSON: non-finite numbers are not representable');
|
|
26
|
+
}
|
|
27
|
+
return JSON.stringify(value);
|
|
28
|
+
}
|
|
29
|
+
if (typeof value === 'bigint') {
|
|
30
|
+
// Store as a decimal string; up to caller to know the type.
|
|
31
|
+
return JSON.stringify(value.toString());
|
|
32
|
+
}
|
|
33
|
+
if (typeof value === 'string')
|
|
34
|
+
return JSON.stringify(value);
|
|
35
|
+
if (Array.isArray(value)) {
|
|
36
|
+
return '[' + value.map(canonicalJSON).join(',') + ']';
|
|
37
|
+
}
|
|
38
|
+
if (typeof value === 'object') {
|
|
39
|
+
const obj = value;
|
|
40
|
+
const keys = Object.keys(obj).filter((k) => obj[k] !== undefined).sort();
|
|
41
|
+
return '{' + keys.map((k) => JSON.stringify(k) + ':' + canonicalJSON(obj[k])).join(',') + '}';
|
|
42
|
+
}
|
|
43
|
+
throw new Error(`canonicalJSON: unsupported value type ${typeof value}`);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Compute the keccak256 hash of an entry (without the `hash` field).
|
|
47
|
+
* Returns lowercase hex.
|
|
48
|
+
*/
|
|
49
|
+
export function hashEntry(entry) {
|
|
50
|
+
return keccak256(Buffer.from(canonicalJSON(entry), 'utf8')).toString('hex');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Stamp an entry with its hash.
|
|
54
|
+
*/
|
|
55
|
+
export function sealEntry(entry) {
|
|
56
|
+
return { ...entry, hash: hashEntry(entry) };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Serialize a stored entry to a single JSON line (newline-terminated).
|
|
60
|
+
*/
|
|
61
|
+
export function serializeEntry(entry) {
|
|
62
|
+
return canonicalJSON(entry) + '\n';
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Parse a single line and verify its self-hash. Does NOT check chain linkage.
|
|
66
|
+
*/
|
|
67
|
+
export function parseLine(line) {
|
|
68
|
+
let parsed;
|
|
69
|
+
try {
|
|
70
|
+
parsed = JSON.parse(line);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
throw new AuditChainError(`malformed JSON: ${err.message}`);
|
|
74
|
+
}
|
|
75
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
76
|
+
throw new AuditChainError('line is not a JSON object');
|
|
77
|
+
}
|
|
78
|
+
const obj = parsed;
|
|
79
|
+
const hash = obj['hash'];
|
|
80
|
+
if (typeof hash !== 'string' || hash.length !== HASH_HEX_LEN) {
|
|
81
|
+
throw new AuditChainError('missing or malformed hash field');
|
|
82
|
+
}
|
|
83
|
+
// Validate required top-level fields exist and have the right shape.
|
|
84
|
+
for (const required of ['seq', 'ts', 'prev_hash', 'kind', 'portal', 'decision']) {
|
|
85
|
+
if (!(required in obj)) {
|
|
86
|
+
throw new AuditChainError(`missing required field: ${required}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (typeof obj['seq'] !== 'number' || !Number.isInteger(obj['seq']) || obj['seq'] < 0) {
|
|
90
|
+
throw new AuditChainError('seq must be a non-negative integer');
|
|
91
|
+
}
|
|
92
|
+
if (typeof obj['prev_hash'] !== 'string' || obj['prev_hash'].length !== HASH_HEX_LEN) {
|
|
93
|
+
throw new AuditChainError('prev_hash must be 64-char hex');
|
|
94
|
+
}
|
|
95
|
+
// Re-hash without the hash field and compare.
|
|
96
|
+
const rest = {
|
|
97
|
+
seq: obj['seq'],
|
|
98
|
+
ts: obj['ts'],
|
|
99
|
+
prev_hash: obj['prev_hash'],
|
|
100
|
+
kind: obj['kind'],
|
|
101
|
+
portal: obj['portal'],
|
|
102
|
+
payload: obj['payload'],
|
|
103
|
+
decision: obj['decision'],
|
|
104
|
+
...(obj['reason'] !== undefined ? { reason: obj['reason'] } : {}),
|
|
105
|
+
...(obj['sig'] !== undefined ? { sig: obj['sig'] } : {}),
|
|
106
|
+
};
|
|
107
|
+
const expected = hashEntry(rest);
|
|
108
|
+
if (hash !== expected) {
|
|
109
|
+
throw new AuditChainError(`hash mismatch: stored=${hash} expected=${expected}`, rest.seq);
|
|
110
|
+
}
|
|
111
|
+
return { ...rest, hash };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Verify a buffer's worth of JSONL audit entries.
|
|
115
|
+
* - Empty buffer → empty chain.
|
|
116
|
+
* - Each entry must self-hash correctly.
|
|
117
|
+
* - Each entry's seq must be expected (0, 1, 2, ...).
|
|
118
|
+
* - Each entry's prev_hash must match the previous entry's hash.
|
|
119
|
+
* - A trailing non-empty fragment (no terminating newline) is a torn write.
|
|
120
|
+
*
|
|
121
|
+
* Returns the entries in order. Throws AuditChainError on any failure.
|
|
122
|
+
*/
|
|
123
|
+
export function verifyChain(buf) {
|
|
124
|
+
const text = typeof buf === 'string' ? buf : buf.toString('utf8');
|
|
125
|
+
if (text === '')
|
|
126
|
+
return [];
|
|
127
|
+
const lines = text.split('\n');
|
|
128
|
+
// Well-formed JSONL ends with a newline, so split yields a trailing empty string.
|
|
129
|
+
const last = lines[lines.length - 1];
|
|
130
|
+
if (last !== '') {
|
|
131
|
+
throw new AuditChainError(`torn write: trailing fragment of ${last.length} bytes without newline`);
|
|
132
|
+
}
|
|
133
|
+
lines.pop();
|
|
134
|
+
const entries = [];
|
|
135
|
+
let expectedPrevHash = ZERO_HASH;
|
|
136
|
+
let expectedSeq = 0;
|
|
137
|
+
for (const line of lines) {
|
|
138
|
+
const entry = parseLine(line);
|
|
139
|
+
if (entry.seq !== expectedSeq) {
|
|
140
|
+
throw new AuditChainError(`seq gap: expected ${expectedSeq}, got ${entry.seq}`, entry.seq);
|
|
141
|
+
}
|
|
142
|
+
if (entry.prev_hash !== expectedPrevHash) {
|
|
143
|
+
throw new AuditChainError(`prev_hash mismatch: expected ${expectedPrevHash}, got ${entry.prev_hash}`, entry.seq);
|
|
144
|
+
}
|
|
145
|
+
entries.push(entry);
|
|
146
|
+
expectedPrevHash = entry.hash;
|
|
147
|
+
expectedSeq++;
|
|
148
|
+
}
|
|
149
|
+
return entries;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Read the chain head from an existing audit file. Verifies the whole chain
|
|
153
|
+
* during read. If the file does not exist or is empty, returns the genesis head.
|
|
154
|
+
*/
|
|
155
|
+
export function readHead(path) {
|
|
156
|
+
let buf;
|
|
157
|
+
try {
|
|
158
|
+
buf = readFileSync(path);
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
if (err.code === 'ENOENT') {
|
|
162
|
+
return { nextSeq: 0, prevHash: ZERO_HASH };
|
|
163
|
+
}
|
|
164
|
+
throw err;
|
|
165
|
+
}
|
|
166
|
+
const entries = verifyChain(buf);
|
|
167
|
+
if (entries.length === 0) {
|
|
168
|
+
return { nextSeq: 0, prevHash: ZERO_HASH };
|
|
169
|
+
}
|
|
170
|
+
const last = entries[entries.length - 1];
|
|
171
|
+
return { nextSeq: last.seq + 1, prevHash: last.hash };
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Append-only audit writer with fsync after every write.
|
|
175
|
+
*
|
|
176
|
+
* Typical use:
|
|
177
|
+
* const w = new AuditWriter('/path/to/audit.log');
|
|
178
|
+
* w.append({ kind: 'eth_sign_message', portal: 'eth:bot', payload, decision: 'allow', sig });
|
|
179
|
+
* w.close();
|
|
180
|
+
*
|
|
181
|
+
* The seq and prev_hash fields are managed by the writer; callers supply
|
|
182
|
+
* everything else.
|
|
183
|
+
*/
|
|
184
|
+
export class AuditWriter {
|
|
185
|
+
path;
|
|
186
|
+
#head;
|
|
187
|
+
#closed = false;
|
|
188
|
+
// Allow tests to inject a fixed clock. Defaults to Date.now.
|
|
189
|
+
#now;
|
|
190
|
+
constructor(path, opts = {}) {
|
|
191
|
+
this.path = path;
|
|
192
|
+
this.#head = readHead(path);
|
|
193
|
+
this.#now = opts.now ?? (() => Date.now());
|
|
194
|
+
}
|
|
195
|
+
get head() {
|
|
196
|
+
return { ...this.#head };
|
|
197
|
+
}
|
|
198
|
+
append(input) {
|
|
199
|
+
if (this.#closed)
|
|
200
|
+
throw new Error('AuditWriter is closed');
|
|
201
|
+
const entry = {
|
|
202
|
+
seq: this.#head.nextSeq,
|
|
203
|
+
ts: this.#now(),
|
|
204
|
+
prev_hash: this.#head.prevHash,
|
|
205
|
+
kind: input.kind,
|
|
206
|
+
portal: input.portal,
|
|
207
|
+
payload: input.payload,
|
|
208
|
+
decision: input.decision,
|
|
209
|
+
...(input.reason !== undefined ? { reason: input.reason } : {}),
|
|
210
|
+
...(input.sig !== undefined ? { sig: input.sig } : {}),
|
|
211
|
+
};
|
|
212
|
+
const stored = sealEntry(entry);
|
|
213
|
+
const line = serializeEntry(stored);
|
|
214
|
+
const fd = openSync(this.path, 'a', 0o600);
|
|
215
|
+
try {
|
|
216
|
+
writeSync(fd, line);
|
|
217
|
+
fsyncSync(fd);
|
|
218
|
+
}
|
|
219
|
+
finally {
|
|
220
|
+
closeSync(fd);
|
|
221
|
+
}
|
|
222
|
+
this.#head = { nextSeq: stored.seq + 1, prevHash: stored.hash };
|
|
223
|
+
return stored;
|
|
224
|
+
}
|
|
225
|
+
close() {
|
|
226
|
+
this.#closed = true;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../../src/audit/log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAClF,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAoB7C,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AACxC,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAE/B,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,KAAK,CAAqB;IACnC,YAAY,GAAW,EAAE,KAAc;QACrC,KAAK,CAAC,oBAAoB,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC;QACnF,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACzD,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAChE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,4DAA4D;QAC5D,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACxD,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,KAAgC,CAAC;QAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC;QACzE,OAAO,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IAChG,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,yCAAyC,OAAO,KAAK,EAAE,CAAC,CAAC;AAC3E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,KAAiB;IACzC,OAAO,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,KAAiB;IACzC,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAuB;IACpD,OAAO,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,eAAe,CAAC,mBAAoB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,eAAe,CAAC,2BAA2B,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,GAAG,GAAG,MAAiC,CAAC;IAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;QAC7D,MAAM,IAAI,eAAe,CAAC,iCAAiC,CAAC,CAAC;IAC/D,CAAC;IACD,qEAAqE;IACrE,KAAK,MAAM,QAAQ,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAU,EAAE,CAAC;QACzF,IAAI,CAAC,CAAC,QAAQ,IAAI,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,eAAe,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACtF,MAAM,IAAI,eAAe,CAAC,oCAAoC,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,WAAW,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;QACrF,MAAM,IAAI,eAAe,CAAC,+BAA+B,CAAC,CAAC;IAC7D,CAAC;IACD,8CAA8C;IAC9C,MAAM,IAAI,GAAe;QACvB,GAAG,EAAE,GAAG,CAAC,KAAK,CAAW;QACzB,EAAE,EAAE,GAAG,CAAC,IAAI,CAAW;QACvB,SAAS,EAAE,GAAG,CAAC,WAAW,CAAW;QACrC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAW;QAC3B,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAW;QAC/B,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC;QACvB,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAkB;QAC1C,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3E,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnE,CAAC;IACF,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,MAAM,IAAI,eAAe,CAAC,yBAAyB,IAAI,aAAa,QAAQ,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAC,GAAoB;IAC9C,MAAM,IAAI,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAClE,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,kFAAkF;IAClF,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrC,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,eAAe,CAAC,oCAAoC,IAAK,CAAC,MAAM,wBAAwB,CAAC,CAAC;IACtG,CAAC;IACD,KAAK,CAAC,GAAG,EAAE,CAAC;IAEZ,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,IAAI,gBAAgB,GAAG,SAAS,CAAC;IACjC,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW,EAAE,CAAC;YAC9B,MAAM,IAAI,eAAe,CAAC,qBAAqB,WAAW,SAAS,KAAK,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7F,CAAC;QACD,IAAI,KAAK,CAAC,SAAS,KAAK,gBAAgB,EAAE,CAAC;YACzC,MAAM,IAAI,eAAe,CACvB,gCAAgC,gBAAgB,SAAS,KAAK,CAAC,SAAS,EAAE,EAC1E,KAAK,CAAC,GAAG,CACV,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,gBAAgB,GAAG,KAAK,CAAC,IAAI,CAAC;QAC9B,WAAW,EAAE,CAAC;IAChB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAUD;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QAC7C,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IAC7C,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;IAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;AACxD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,OAAO,WAAW;IACb,IAAI,CAAS;IACtB,KAAK,CAAY;IACjB,OAAO,GAAG,KAAK,CAAC;IAChB,6DAA6D;IAC7D,IAAI,CAAe;IAEnB,YAAY,IAAY,EAAE,OAA+B,EAAE;QACzD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,IAAI;QACN,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED,MAAM,CAAC,KAON;QACC,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAe;YACxB,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;YACvB,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE;YACf,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ;YAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/D,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACvD,CAAC;QACF,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QAEpC,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3C,IAAI,CAAC;YACH,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACpB,SAAS,CAAC,EAAE,CAAC,CAAC;QAChB,CAAC;gBAAS,CAAC;YACT,SAAS,CAAC,EAAE,CAAC,CAAC;QAChB,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;QAChE,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sigild.d.ts","sourceRoot":"","sources":["../../../src/bin/sigild.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { readPassphrase } from '../daemon/passphrase.js';
|
|
5
|
+
import { runDaemon } from '../daemon/runtime.js';
|
|
6
|
+
const sigilHome = process.env['SIGIL_HOME'] ?? join(homedir(), '.sigil');
|
|
7
|
+
let shutting = false;
|
|
8
|
+
async function main() {
|
|
9
|
+
const handle = await runDaemon({
|
|
10
|
+
sigilHome,
|
|
11
|
+
passphrase: () => readPassphrase('sigil passphrase: '),
|
|
12
|
+
onLog: (e) => process.stderr.write(JSON.stringify(e) + '\n'),
|
|
13
|
+
});
|
|
14
|
+
process.stderr.write(`sigild ready: ${handle.portals} portal(s) loaded, listening on ${handle.socketPath}\n`);
|
|
15
|
+
const shutdown = async (signal) => {
|
|
16
|
+
if (shutting)
|
|
17
|
+
return;
|
|
18
|
+
shutting = true;
|
|
19
|
+
process.stderr.write(`sigild: ${signal} received, shutting down\n`);
|
|
20
|
+
await handle.shutdown();
|
|
21
|
+
process.exit(0);
|
|
22
|
+
};
|
|
23
|
+
process.on('SIGINT', () => { void shutdown('SIGINT'); });
|
|
24
|
+
process.on('SIGTERM', () => { void shutdown('SIGTERM'); });
|
|
25
|
+
}
|
|
26
|
+
main().catch((err) => {
|
|
27
|
+
process.stderr.write(`sigild: ${err.message}\n`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=sigild.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sigild.js","sourceRoot":"","sources":["../../../src/bin/sigild.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAEzE,IAAI,QAAQ,GAAG,KAAK,CAAC;AAErB,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC;QAC7B,SAAS;QACT,UAAU,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,oBAAoB,CAAC;QACtD,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;KAC7D,CAAC,CAAC;IAEH,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iBAAiB,MAAM,CAAC,OAAO,mCAAmC,MAAM,CAAC,UAAU,IAAI,CACxF,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAiB,EAAE;QACvD,IAAI,QAAQ;YAAE,OAAO;QACrB,QAAQ,GAAG,IAAI,CAAC;QAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,MAAM,4BAA4B,CAAC,CAAC;QACpE,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;IAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const AEAD_KEY_LEN = 32;
|
|
2
|
+
export declare const AEAD_NONCE_LEN = 24;
|
|
3
|
+
export declare const AEAD_TAG_LEN = 16;
|
|
4
|
+
export declare class AeadVerifyError extends Error {
|
|
5
|
+
constructor(cause?: unknown);
|
|
6
|
+
}
|
|
7
|
+
export declare function aeadEncrypt(key: Buffer | Uint8Array, nonce: Buffer | Uint8Array, plaintext: Buffer | Uint8Array, aad?: Buffer | Uint8Array): Buffer;
|
|
8
|
+
export declare function aeadDecrypt(key: Buffer | Uint8Array, nonce: Buffer | Uint8Array, ciphertext: Buffer | Uint8Array, aad?: Buffer | Uint8Array): Buffer;
|
|
9
|
+
//# sourceMappingURL=aead.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aead.d.ts","sourceRoot":"","sources":["../../../src/crypto/aead.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY,KAAK,CAAC;AAC/B,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,YAAY,KAAK,CAAC;AAE/B,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,KAAK,CAAC,EAAE,OAAO;CAK5B;AAED,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,GAAG,UAAU,EACxB,KAAK,EAAE,MAAM,GAAG,UAAU,EAC1B,SAAS,EAAE,MAAM,GAAG,UAAU,EAC9B,GAAG,CAAC,EAAE,MAAM,GAAG,UAAU,GACxB,MAAM,CASR;AAED,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,GAAG,UAAU,EACxB,KAAK,EAAE,MAAM,GAAG,UAAU,EAC1B,UAAU,EAAE,MAAM,GAAG,UAAU,EAC/B,GAAG,CAAC,EAAE,MAAM,GAAG,UAAU,GACxB,MAAM,CAaR"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { xchacha20poly1305 } from '@noble/ciphers/chacha.js';
|
|
2
|
+
export const AEAD_KEY_LEN = 32;
|
|
3
|
+
export const AEAD_NONCE_LEN = 24;
|
|
4
|
+
export const AEAD_TAG_LEN = 16;
|
|
5
|
+
export class AeadVerifyError extends Error {
|
|
6
|
+
constructor(cause) {
|
|
7
|
+
super('AEAD verification failed (wrong key, wrong nonce, tampered ciphertext, or mismatched AAD)');
|
|
8
|
+
this.name = 'AeadVerifyError';
|
|
9
|
+
if (cause !== undefined)
|
|
10
|
+
this.cause = cause;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function aeadEncrypt(key, nonce, plaintext, aad) {
|
|
14
|
+
if (key.length !== AEAD_KEY_LEN) {
|
|
15
|
+
throw new Error(`key must be ${AEAD_KEY_LEN} bytes, got ${key.length}`);
|
|
16
|
+
}
|
|
17
|
+
if (nonce.length !== AEAD_NONCE_LEN) {
|
|
18
|
+
throw new Error(`nonce must be ${AEAD_NONCE_LEN} bytes, got ${nonce.length}`);
|
|
19
|
+
}
|
|
20
|
+
const cipher = xchacha20poly1305(key, nonce, aad);
|
|
21
|
+
return Buffer.from(cipher.encrypt(plaintext));
|
|
22
|
+
}
|
|
23
|
+
export function aeadDecrypt(key, nonce, ciphertext, aad) {
|
|
24
|
+
if (key.length !== AEAD_KEY_LEN) {
|
|
25
|
+
throw new Error(`key must be ${AEAD_KEY_LEN} bytes, got ${key.length}`);
|
|
26
|
+
}
|
|
27
|
+
if (nonce.length !== AEAD_NONCE_LEN) {
|
|
28
|
+
throw new Error(`nonce must be ${AEAD_NONCE_LEN} bytes, got ${nonce.length}`);
|
|
29
|
+
}
|
|
30
|
+
const cipher = xchacha20poly1305(key, nonce, aad);
|
|
31
|
+
try {
|
|
32
|
+
return Buffer.from(cipher.decrypt(ciphertext));
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
throw new AeadVerifyError(err);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=aead.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aead.js","sourceRoot":"","sources":["../../../src/crypto/aead.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAC/B,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AACjC,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAE/B,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxC,YAAY,KAAe;QACzB,KAAK,CAAC,2FAA2F,CAAC,CAAC;QACnG,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAC9C,CAAC;CACF;AAED,MAAM,UAAU,WAAW,CACzB,GAAwB,EACxB,KAA0B,EAC1B,SAA8B,EAC9B,GAAyB;IAEzB,IAAI,GAAG,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,eAAe,YAAY,eAAe,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,iBAAiB,cAAc,eAAe,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAClD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,GAAwB,EACxB,KAA0B,EAC1B,UAA+B,EAC/B,GAAyB;IAEzB,IAAI,GAAG,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,eAAe,YAAY,eAAe,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,iBAAiB,cAAc,eAAe,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { SecretBuffer, SecretBufferDisposedError, SecretBufferSerializeError, } from './secret-buffer.js';
|
|
2
|
+
export { DEFAULT_KDF_PARAMS, SALT_LEN, DERIVED_KEY_LEN, deriveKey, type KdfParams, } from './kdf.js';
|
|
3
|
+
export { AEAD_KEY_LEN, AEAD_NONCE_LEN, AEAD_TAG_LEN, AeadVerifyError, aeadEncrypt, aeadDecrypt, } from './aead.js';
|
|
4
|
+
export { HEADER_LEN, KeyfileFormatError, WrongPassphraseError, sealKey, unsealKey, } from './keyfile.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,SAAS,EACT,KAAK,SAAS,GACf,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,eAAe,EACf,WAAW,EACX,WAAW,GACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,oBAAoB,EACpB,OAAO,EACP,SAAS,GACV,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { SecretBuffer, SecretBufferDisposedError, SecretBufferSerializeError, } from './secret-buffer.js';
|
|
2
|
+
export { DEFAULT_KDF_PARAMS, SALT_LEN, DERIVED_KEY_LEN, deriveKey, } from './kdf.js';
|
|
3
|
+
export { AEAD_KEY_LEN, AEAD_NONCE_LEN, AEAD_TAG_LEN, AeadVerifyError, aeadEncrypt, aeadDecrypt, } from './aead.js';
|
|
4
|
+
export { HEADER_LEN, KeyfileFormatError, WrongPassphraseError, sealKey, unsealKey, } from './keyfile.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,SAAS,GAEV,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,eAAe,EACf,WAAW,EACX,WAAW,GACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,oBAAoB,EACpB,OAAO,EACP,SAAS,GACV,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface KdfParams {
|
|
2
|
+
m: number;
|
|
3
|
+
t: number;
|
|
4
|
+
p: number;
|
|
5
|
+
}
|
|
6
|
+
export declare const DEFAULT_KDF_PARAMS: KdfParams;
|
|
7
|
+
export declare const SALT_LEN = 16;
|
|
8
|
+
export declare const DERIVED_KEY_LEN = 32;
|
|
9
|
+
export declare function deriveKey(passphrase: Buffer | Uint8Array, salt: Buffer | Uint8Array, params?: KdfParams): Buffer;
|
|
10
|
+
//# sourceMappingURL=kdf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kdf.d.ts","sourceRoot":"","sources":["../../../src/crypto/kdf.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,eAAO,MAAM,kBAAkB,EAAE,SAIhC,CAAC;AAEF,eAAO,MAAM,QAAQ,KAAK,CAAC;AAC3B,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,GAAG,UAAU,EAC/B,IAAI,EAAE,MAAM,GAAG,UAAU,EACzB,MAAM,GAAE,SAA8B,GACrC,MAAM,CAeR"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { argon2id } from '@noble/hashes/argon2.js';
|
|
2
|
+
export const DEFAULT_KDF_PARAMS = {
|
|
3
|
+
m: 64 * 1024,
|
|
4
|
+
t: 3,
|
|
5
|
+
p: 4,
|
|
6
|
+
};
|
|
7
|
+
export const SALT_LEN = 16;
|
|
8
|
+
export const DERIVED_KEY_LEN = 32;
|
|
9
|
+
export function deriveKey(passphrase, salt, params = DEFAULT_KDF_PARAMS) {
|
|
10
|
+
if (salt.length !== SALT_LEN) {
|
|
11
|
+
throw new Error(`salt must be ${SALT_LEN} bytes, got ${salt.length}`);
|
|
12
|
+
}
|
|
13
|
+
if (params.m < 8)
|
|
14
|
+
throw new Error('argon2id m must be >= 8 KiB');
|
|
15
|
+
if (params.t < 1)
|
|
16
|
+
throw new Error('argon2id t must be >= 1');
|
|
17
|
+
if (params.p < 1)
|
|
18
|
+
throw new Error('argon2id p must be >= 1');
|
|
19
|
+
const out = argon2id(passphrase, salt, {
|
|
20
|
+
m: params.m,
|
|
21
|
+
t: params.t,
|
|
22
|
+
p: params.p,
|
|
23
|
+
dkLen: DERIVED_KEY_LEN,
|
|
24
|
+
});
|
|
25
|
+
return Buffer.from(out);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=kdf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kdf.js","sourceRoot":"","sources":["../../../src/crypto/kdf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAQnD,MAAM,CAAC,MAAM,kBAAkB,GAAc;IAC3C,CAAC,EAAE,EAAE,GAAG,IAAI;IACZ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;CACL,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,EAAE,CAAC;AAC3B,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAElC,MAAM,UAAU,SAAS,CACvB,UAA+B,EAC/B,IAAyB,EACzB,SAAoB,kBAAkB;IAEtC,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,gBAAgB,QAAQ,eAAe,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjE,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7D,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAE7D,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,EAAE,IAAI,EAAE;QACrC,CAAC,EAAE,MAAM,CAAC,CAAC;QACX,CAAC,EAAE,MAAM,CAAC,CAAC;QACX,CAAC,EAAE,MAAM,CAAC,CAAC;QACX,KAAK,EAAE,eAAe;KACvB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type KdfParams } from './kdf.js';
|
|
2
|
+
import { SecretBuffer } from './secret-buffer.js';
|
|
3
|
+
export declare const HEADER_LEN: number;
|
|
4
|
+
export declare class KeyfileFormatError extends Error {
|
|
5
|
+
constructor(reason: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class WrongPassphraseError extends Error {
|
|
8
|
+
constructor();
|
|
9
|
+
}
|
|
10
|
+
export declare function sealKey(plainKey: Buffer | Uint8Array, passphrase: Buffer | Uint8Array, params?: KdfParams): Buffer;
|
|
11
|
+
export declare function unsealKey(keyfileBytes: Buffer, passphrase: Buffer | Uint8Array): SecretBuffer;
|
|
12
|
+
//# sourceMappingURL=keyfile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyfile.d.ts","sourceRoot":"","sources":["../../../src/crypto/keyfile.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2C,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAOlD,eAAO,MAAM,UAAU,QAUP,CAAC;AAGjB,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,MAAM,EAAE,MAAM;CAI3B;AAED,qBAAa,oBAAqB,SAAQ,KAAK;;CAK9C;AA6DD,wBAAgB,OAAO,CACrB,QAAQ,EAAE,MAAM,GAAG,UAAU,EAC7B,UAAU,EAAE,MAAM,GAAG,UAAU,EAC/B,MAAM,GAAE,SAA8B,GACrC,MAAM,CAWR;AAED,wBAAgB,SAAS,CACvB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GAAG,UAAU,GAC9B,YAAY,CAcd"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { AEAD_NONCE_LEN, aeadDecrypt, aeadEncrypt, AeadVerifyError } from './aead.js';
|
|
3
|
+
import { DEFAULT_KDF_PARAMS, deriveKey, SALT_LEN } from './kdf.js';
|
|
4
|
+
import { SecretBuffer } from './secret-buffer.js';
|
|
5
|
+
const MAGIC = Buffer.from('SIGIL', 'ascii');
|
|
6
|
+
const FORMAT_VERSION = 0x01;
|
|
7
|
+
const KDF_ARGON2ID = 0x01;
|
|
8
|
+
const AEAD_XCHACHA20POLY1305 = 0x01;
|
|
9
|
+
export const HEADER_LEN = MAGIC.length + // 5
|
|
10
|
+
1 + // format version
|
|
11
|
+
1 + // kdf type
|
|
12
|
+
4 + // kdf.m (uint32 BE, KiB)
|
|
13
|
+
1 + // kdf.t
|
|
14
|
+
1 + // kdf.p
|
|
15
|
+
1 + // aead type
|
|
16
|
+
2 + // reserved
|
|
17
|
+
SALT_LEN + // 16
|
|
18
|
+
AEAD_NONCE_LEN; // 24
|
|
19
|
+
// total: 56
|
|
20
|
+
export class KeyfileFormatError extends Error {
|
|
21
|
+
constructor(reason) {
|
|
22
|
+
super(`keyfile format error: ${reason}`);
|
|
23
|
+
this.name = 'KeyfileFormatError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export class WrongPassphraseError extends Error {
|
|
27
|
+
constructor() {
|
|
28
|
+
super('wrong passphrase or tampered keyfile');
|
|
29
|
+
this.name = 'WrongPassphraseError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function buildHeader(salt, nonce, params) {
|
|
33
|
+
const h = Buffer.alloc(HEADER_LEN);
|
|
34
|
+
let off = 0;
|
|
35
|
+
MAGIC.copy(h, off);
|
|
36
|
+
off += MAGIC.length;
|
|
37
|
+
h.writeUInt8(FORMAT_VERSION, off++);
|
|
38
|
+
h.writeUInt8(KDF_ARGON2ID, off++);
|
|
39
|
+
h.writeUInt32BE(params.m, off);
|
|
40
|
+
off += 4;
|
|
41
|
+
h.writeUInt8(params.t, off++);
|
|
42
|
+
h.writeUInt8(params.p, off++);
|
|
43
|
+
h.writeUInt8(AEAD_XCHACHA20POLY1305, off++);
|
|
44
|
+
h.writeUInt16BE(0, off);
|
|
45
|
+
off += 2;
|
|
46
|
+
salt.copy(h, off);
|
|
47
|
+
off += SALT_LEN;
|
|
48
|
+
nonce.copy(h, off);
|
|
49
|
+
off += AEAD_NONCE_LEN;
|
|
50
|
+
return h;
|
|
51
|
+
}
|
|
52
|
+
function parseHeader(buf) {
|
|
53
|
+
if (buf.length < HEADER_LEN) {
|
|
54
|
+
throw new KeyfileFormatError(`truncated: need at least ${HEADER_LEN} bytes, got ${buf.length}`);
|
|
55
|
+
}
|
|
56
|
+
let off = 0;
|
|
57
|
+
if (!buf.subarray(off, off + MAGIC.length).equals(MAGIC)) {
|
|
58
|
+
throw new KeyfileFormatError('bad magic');
|
|
59
|
+
}
|
|
60
|
+
off += MAGIC.length;
|
|
61
|
+
const ver = buf.readUInt8(off++);
|
|
62
|
+
if (ver !== FORMAT_VERSION) {
|
|
63
|
+
throw new KeyfileFormatError(`unsupported format version ${ver}`);
|
|
64
|
+
}
|
|
65
|
+
const kdfType = buf.readUInt8(off++);
|
|
66
|
+
if (kdfType !== KDF_ARGON2ID) {
|
|
67
|
+
throw new KeyfileFormatError(`unsupported kdf type ${kdfType}`);
|
|
68
|
+
}
|
|
69
|
+
const m = buf.readUInt32BE(off);
|
|
70
|
+
off += 4;
|
|
71
|
+
const t = buf.readUInt8(off++);
|
|
72
|
+
const p = buf.readUInt8(off++);
|
|
73
|
+
const aeadType = buf.readUInt8(off++);
|
|
74
|
+
if (aeadType !== AEAD_XCHACHA20POLY1305) {
|
|
75
|
+
throw new KeyfileFormatError(`unsupported aead type ${aeadType}`);
|
|
76
|
+
}
|
|
77
|
+
off += 2; // reserved
|
|
78
|
+
const salt = Buffer.from(buf.subarray(off, off + SALT_LEN));
|
|
79
|
+
off += SALT_LEN;
|
|
80
|
+
const nonce = Buffer.from(buf.subarray(off, off + AEAD_NONCE_LEN));
|
|
81
|
+
return { kdf: { m, t, p }, salt, nonce };
|
|
82
|
+
}
|
|
83
|
+
export function sealKey(plainKey, passphrase, params = DEFAULT_KDF_PARAMS) {
|
|
84
|
+
const salt = randomBytes(SALT_LEN);
|
|
85
|
+
const nonce = randomBytes(AEAD_NONCE_LEN);
|
|
86
|
+
const header = buildHeader(salt, nonce, params);
|
|
87
|
+
const derivedKey = deriveKey(passphrase, salt, params);
|
|
88
|
+
try {
|
|
89
|
+
const ciphertext = aeadEncrypt(derivedKey, nonce, plainKey, header);
|
|
90
|
+
return Buffer.concat([header, ciphertext]);
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
derivedKey.fill(0);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export function unsealKey(keyfileBytes, passphrase) {
|
|
97
|
+
const { kdf, salt, nonce } = parseHeader(keyfileBytes);
|
|
98
|
+
const header = keyfileBytes.subarray(0, HEADER_LEN);
|
|
99
|
+
const ciphertext = keyfileBytes.subarray(HEADER_LEN);
|
|
100
|
+
const derivedKey = deriveKey(passphrase, salt, kdf);
|
|
101
|
+
try {
|
|
102
|
+
const plain = aeadDecrypt(derivedKey, nonce, ciphertext, header);
|
|
103
|
+
return new SecretBuffer(plain);
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
if (err instanceof AeadVerifyError)
|
|
107
|
+
throw new WrongPassphraseError();
|
|
108
|
+
throw err;
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
derivedKey.fill(0);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=keyfile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyfile.js","sourceRoot":"","sources":["../../../src/crypto/keyfile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { inspect } from 'node:util';
|
|
2
|
+
export declare class SecretBufferDisposedError extends Error {
|
|
3
|
+
constructor();
|
|
4
|
+
}
|
|
5
|
+
export declare class SecretBufferSerializeError extends Error {
|
|
6
|
+
constructor();
|
|
7
|
+
}
|
|
8
|
+
export declare class SecretBuffer {
|
|
9
|
+
#private;
|
|
10
|
+
constructor(source: Buffer | Uint8Array);
|
|
11
|
+
bytes(): Buffer;
|
|
12
|
+
get length(): number;
|
|
13
|
+
dispose(): void;
|
|
14
|
+
get isDisposed(): boolean;
|
|
15
|
+
toString(): never;
|
|
16
|
+
toJSON(): never;
|
|
17
|
+
[inspect.custom](): string;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=secret-buffer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-buffer.d.ts","sourceRoot":"","sources":["../../../src/crypto/secret-buffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,qBAAa,yBAA0B,SAAQ,KAAK;;CAKnD;AAED,qBAAa,0BAA2B,SAAQ,KAAK;;CAKpD;AAED,qBAAa,YAAY;;gBAGX,MAAM,EAAE,MAAM,GAAG,UAAU;IAIvC,KAAK,IAAI,MAAM;IAKf,IAAI,MAAM,IAAI,MAAM,CAGnB;IAED,OAAO,IAAI,IAAI;IAOf,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,QAAQ,IAAI,KAAK;IAIjB,MAAM,IAAI,KAAK;IAIf,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM;CAG3B"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { inspect } from 'node:util';
|
|
2
|
+
export class SecretBufferDisposedError extends Error {
|
|
3
|
+
constructor() {
|
|
4
|
+
super('SecretBuffer has been disposed');
|
|
5
|
+
this.name = 'SecretBufferDisposedError';
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export class SecretBufferSerializeError extends Error {
|
|
9
|
+
constructor() {
|
|
10
|
+
super('SecretBuffer cannot be serialized; use .bytes() if you really need the value');
|
|
11
|
+
this.name = 'SecretBufferSerializeError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class SecretBuffer {
|
|
15
|
+
#buf;
|
|
16
|
+
constructor(source) {
|
|
17
|
+
this.#buf = Buffer.from(source);
|
|
18
|
+
}
|
|
19
|
+
bytes() {
|
|
20
|
+
if (this.#buf === null)
|
|
21
|
+
throw new SecretBufferDisposedError();
|
|
22
|
+
return this.#buf;
|
|
23
|
+
}
|
|
24
|
+
get length() {
|
|
25
|
+
if (this.#buf === null)
|
|
26
|
+
throw new SecretBufferDisposedError();
|
|
27
|
+
return this.#buf.length;
|
|
28
|
+
}
|
|
29
|
+
dispose() {
|
|
30
|
+
if (this.#buf !== null) {
|
|
31
|
+
this.#buf.fill(0);
|
|
32
|
+
this.#buf = null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
get isDisposed() {
|
|
36
|
+
return this.#buf === null;
|
|
37
|
+
}
|
|
38
|
+
toString() {
|
|
39
|
+
throw new SecretBufferSerializeError();
|
|
40
|
+
}
|
|
41
|
+
toJSON() {
|
|
42
|
+
throw new SecretBufferSerializeError();
|
|
43
|
+
}
|
|
44
|
+
[inspect.custom]() {
|
|
45
|
+
return this.#buf === null ? '<SecretBuffer disposed>' : '<SecretBuffer redacted>';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=secret-buffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-buffer.js","sourceRoot":"","sources":["../../../src/crypto/secret-buffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAClD;QACE,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IACnD;QACE,KAAK,CAAC,8EAA8E,CAAC,CAAC;QACtF,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF;AAED,MAAM,OAAO,YAAY;IACvB,IAAI,CAAgB;IAEpB,YAAY,MAA2B;QACrC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;YAAE,MAAM,IAAI,yBAAyB,EAAE,CAAC;QAC9D,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,IAAI,MAAM;QACR,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;YAAE,MAAM,IAAI,yBAAyB,EAAE,CAAC;QAC9D,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC1B,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,CAAC;IACH,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;IAC5B,CAAC;IAED,QAAQ;QACN,MAAM,IAAI,0BAA0B,EAAE,CAAC;IACzC,CAAC;IAED,MAAM;QACJ,MAAM,IAAI,0BAA0B,EAAE,CAAC;IACzC,CAAC;IAED,CAAC,OAAO,CAAC,MAAM,CAAC;QACd,OAAO,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,yBAAyB,CAAC;IACpF,CAAC;CACF"}
|