@sentinel-atl/registry 0.3.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/README.md +102 -0
- package/dist/badge.d.ts +37 -0
- package/dist/badge.d.ts.map +1 -0
- package/dist/badge.js +114 -0
- package/dist/badge.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +66 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +58 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +347 -0
- package/dist/server.js.map +1 -0
- package/dist/store.d.ts +104 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +177 -0
- package/dist/store.js.map +1 -0
- package/package.json +47 -0
- package/src/__tests__/registry.test.ts +304 -0
- package/src/badge.ts +139 -0
- package/src/cli.ts +74 -0
- package/src/index.ts +31 -0
- package/src/server.ts +407 -0
- package/src/store.ts +267 -0
- package/tsconfig.json +9 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trust Registry HTTP API — REST endpoints for publishing and querying STCs.
|
|
3
|
+
*
|
|
4
|
+
* Endpoints:
|
|
5
|
+
* POST /api/v1/certificates Register a new STC
|
|
6
|
+
* GET /api/v1/certificates/:id Get certificate by ID
|
|
7
|
+
* GET /api/v1/certificates Query certificates
|
|
8
|
+
* DELETE /api/v1/certificates/:id Remove a certificate
|
|
9
|
+
*
|
|
10
|
+
* GET /api/v1/packages/:name Get latest certificate for a package
|
|
11
|
+
* GET /api/v1/packages/:name/history Get all certificates for a package
|
|
12
|
+
* GET /api/v1/packages/:name/badge SVG badge for a package
|
|
13
|
+
* GET /api/v1/packages/:name/badge/score Score badge
|
|
14
|
+
*
|
|
15
|
+
* GET /api/v1/stats Registry stats
|
|
16
|
+
* GET /health Health check
|
|
17
|
+
*/
|
|
18
|
+
import { CertificateStore } from './store.js';
|
|
19
|
+
import { gradeBadge, scoreBadge, verifiedBadge, notFoundBadge } from './badge.js';
|
|
20
|
+
import { authenticate, hasScope, sendUnauthorized, sendForbidden, applyCors, defaultCorsConfig, createSecureServer, applySecurityHeaders, } from '@sentinel-atl/hardening';
|
|
21
|
+
// ─── Server ──────────────────────────────────────────────────────────
|
|
22
|
+
export class RegistryServer {
|
|
23
|
+
server = null;
|
|
24
|
+
store;
|
|
25
|
+
port;
|
|
26
|
+
authConfig;
|
|
27
|
+
corsConfig;
|
|
28
|
+
tlsConfig;
|
|
29
|
+
constructor(options) {
|
|
30
|
+
this.port = options?.port ?? 3200;
|
|
31
|
+
this.store = options?.store ?? new CertificateStore();
|
|
32
|
+
this.authConfig = options?.auth ?? { enabled: false, keys: [] };
|
|
33
|
+
this.corsConfig = options?.cors ?? defaultCorsConfig();
|
|
34
|
+
this.tlsConfig = options?.tls;
|
|
35
|
+
// Badge endpoints are always public (for README embeds)
|
|
36
|
+
if (this.authConfig.enabled && !this.authConfig.publicPaths) {
|
|
37
|
+
this.authConfig.publicPaths = ['/health'];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
getStore() {
|
|
41
|
+
return this.store;
|
|
42
|
+
}
|
|
43
|
+
async start() {
|
|
44
|
+
// Load persisted certificates from backend (no-op if in-memory only)
|
|
45
|
+
await this.store.load();
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
this.server = createSecureServer((req, res) => this.handleRequest(req, res), this.tlsConfig);
|
|
48
|
+
this.server.on('error', reject);
|
|
49
|
+
this.server.listen(this.port, () => {
|
|
50
|
+
resolve({ port: this.port });
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
async stop() {
|
|
55
|
+
return new Promise((resolve) => {
|
|
56
|
+
if (this.server) {
|
|
57
|
+
this.server.close(() => resolve());
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
resolve();
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
isTLS() {
|
|
65
|
+
return !!this.tlsConfig?.certPath || !!this.tlsConfig?.cert;
|
|
66
|
+
}
|
|
67
|
+
// ─── Router ────────────────────────────────────────────────────
|
|
68
|
+
async handleRequest(req, res) {
|
|
69
|
+
const url = new URL(req.url ?? '/', `http://localhost`);
|
|
70
|
+
const path = url.pathname;
|
|
71
|
+
const method = req.method ?? 'GET';
|
|
72
|
+
// CORS (configurable origins)
|
|
73
|
+
if (applyCors(req, res, this.corsConfig))
|
|
74
|
+
return; // preflight handled
|
|
75
|
+
// Security headers
|
|
76
|
+
applySecurityHeaders(res, { hsts: this.isTLS() });
|
|
77
|
+
// Authentication
|
|
78
|
+
const authResult = authenticate(req, this.authConfig);
|
|
79
|
+
// Badge endpoints are public even when auth is enabled
|
|
80
|
+
const isBadgePath = path.includes('/badge');
|
|
81
|
+
if (!authResult.authenticated && !isBadgePath) {
|
|
82
|
+
return sendUnauthorized(res, this.authConfig, authResult.error);
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
// Health
|
|
86
|
+
if (path === '/health' && method === 'GET') {
|
|
87
|
+
return this.sendJson(res, 200, { status: 'ok', certificates: this.store.count() });
|
|
88
|
+
}
|
|
89
|
+
// Stats
|
|
90
|
+
if (path === '/api/v1/stats' && method === 'GET') {
|
|
91
|
+
return this.sendJson(res, 200, this.store.getStats());
|
|
92
|
+
}
|
|
93
|
+
// POST /api/v1/certificates — register (requires write scope)
|
|
94
|
+
if (path === '/api/v1/certificates' && method === 'POST') {
|
|
95
|
+
if (!hasScope(authResult, 'write'))
|
|
96
|
+
return sendForbidden(res, 'Write scope required');
|
|
97
|
+
return await this.handleRegister(req, res);
|
|
98
|
+
}
|
|
99
|
+
// GET /api/v1/certificates — query
|
|
100
|
+
if (path === '/api/v1/certificates' && method === 'GET') {
|
|
101
|
+
return this.handleQuery(url, res);
|
|
102
|
+
}
|
|
103
|
+
// GET/DELETE /api/v1/certificates/:id
|
|
104
|
+
const certMatch = path.match(/^\/api\/v1\/certificates\/(.+)$/);
|
|
105
|
+
if (certMatch) {
|
|
106
|
+
const id = decodeURIComponent(certMatch[1]);
|
|
107
|
+
if (method === 'GET')
|
|
108
|
+
return this.handleGetById(id, res);
|
|
109
|
+
if (method === 'DELETE') {
|
|
110
|
+
if (!hasScope(authResult, 'admin'))
|
|
111
|
+
return sendForbidden(res, 'Admin scope required');
|
|
112
|
+
return this.handleDelete(id, res);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Package routes: /api/v1/packages/:name[/history|/badge|/badge/score]
|
|
116
|
+
const pkgMatch = path.match(/^\/api\/v1\/packages\/(@[^/]+\/[^/]+|[^/]+)(\/.*)?$/);
|
|
117
|
+
if (pkgMatch) {
|
|
118
|
+
const packageName = decodeURIComponent(pkgMatch[1]);
|
|
119
|
+
const suffix = pkgMatch[2] ?? '';
|
|
120
|
+
if (suffix === '' && method === 'GET')
|
|
121
|
+
return this.handleGetPackage(packageName, res);
|
|
122
|
+
if (suffix === '/history' && method === 'GET')
|
|
123
|
+
return this.handlePackageHistory(packageName, res);
|
|
124
|
+
if (suffix === '/badge' && method === 'GET')
|
|
125
|
+
return this.handleBadge(packageName, url, res);
|
|
126
|
+
if (suffix === '/badge/score' && method === 'GET')
|
|
127
|
+
return this.handleScoreBadge(packageName, url, res);
|
|
128
|
+
}
|
|
129
|
+
this.sendJson(res, 404, { error: 'Not found' });
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
this.sendJson(res, 500, { error: 'Internal server error' });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// ─── Handlers ──────────────────────────────────────────────────
|
|
136
|
+
async handleRegister(req, res) {
|
|
137
|
+
// Content-Type enforcement
|
|
138
|
+
const contentType = req.headers['content-type'];
|
|
139
|
+
if (!contentType || !contentType.includes('application/json')) {
|
|
140
|
+
return this.sendJson(res, 415, { error: 'Content-Type must be application/json' });
|
|
141
|
+
}
|
|
142
|
+
const body = await readBody(req);
|
|
143
|
+
let certificate;
|
|
144
|
+
try {
|
|
145
|
+
certificate = JSON.parse(body);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return this.sendJson(res, 400, { error: 'Invalid JSON' });
|
|
149
|
+
}
|
|
150
|
+
// Comprehensive STC validation
|
|
151
|
+
const errors = validateSTC(certificate);
|
|
152
|
+
if (errors.length > 0) {
|
|
153
|
+
return this.sendJson(res, 400, { error: 'Invalid STC', details: errors });
|
|
154
|
+
}
|
|
155
|
+
// Check for duplicates
|
|
156
|
+
if (this.store.get(certificate.id)) {
|
|
157
|
+
return this.sendJson(res, 409, { error: 'Certificate already registered', id: certificate.id });
|
|
158
|
+
}
|
|
159
|
+
const entry = await this.store.register(certificate);
|
|
160
|
+
this.sendJson(res, 201, {
|
|
161
|
+
id: entry.id,
|
|
162
|
+
packageName: entry.packageName,
|
|
163
|
+
trustScore: entry.trustScore,
|
|
164
|
+
grade: entry.grade,
|
|
165
|
+
verified: entry.verified,
|
|
166
|
+
registeredAt: entry.registeredAt,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
handleGetById(id, res) {
|
|
170
|
+
const entry = this.store.get(id);
|
|
171
|
+
if (!entry) {
|
|
172
|
+
return this.sendJson(res, 404, { error: 'Certificate not found' });
|
|
173
|
+
}
|
|
174
|
+
this.sendJson(res, 200, this.formatEntry(entry));
|
|
175
|
+
}
|
|
176
|
+
async handleDelete(id, res) {
|
|
177
|
+
const removed = await this.store.remove(id);
|
|
178
|
+
if (!removed) {
|
|
179
|
+
return this.sendJson(res, 404, { error: 'Certificate not found' });
|
|
180
|
+
}
|
|
181
|
+
this.sendJson(res, 200, { deleted: true, id });
|
|
182
|
+
}
|
|
183
|
+
handleQuery(url, res) {
|
|
184
|
+
const parseIntSafe = (val) => {
|
|
185
|
+
if (val === null)
|
|
186
|
+
return undefined;
|
|
187
|
+
const n = parseInt(val, 10);
|
|
188
|
+
return Number.isNaN(n) ? undefined : n;
|
|
189
|
+
};
|
|
190
|
+
const q = {
|
|
191
|
+
packageName: url.searchParams.get('package') ?? undefined,
|
|
192
|
+
minScore: parseIntSafe(url.searchParams.get('minScore')),
|
|
193
|
+
minGrade: url.searchParams.get('minGrade') ?? undefined,
|
|
194
|
+
verified: url.searchParams.has('verified') ? url.searchParams.get('verified') === 'true' : undefined,
|
|
195
|
+
limit: parseIntSafe(url.searchParams.get('limit')),
|
|
196
|
+
offset: parseIntSafe(url.searchParams.get('offset')),
|
|
197
|
+
};
|
|
198
|
+
const results = this.store.query(q);
|
|
199
|
+
this.sendJson(res, 200, {
|
|
200
|
+
total: this.store.count(),
|
|
201
|
+
count: results.length,
|
|
202
|
+
certificates: results.map(e => this.formatEntry(e)),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
handleGetPackage(packageName, res) {
|
|
206
|
+
const entry = this.store.getLatestForPackage(packageName);
|
|
207
|
+
if (!entry) {
|
|
208
|
+
return this.sendJson(res, 404, { error: 'No certificates found for package', packageName });
|
|
209
|
+
}
|
|
210
|
+
this.sendJson(res, 200, this.formatEntry(entry));
|
|
211
|
+
}
|
|
212
|
+
handlePackageHistory(packageName, res) {
|
|
213
|
+
const entries = this.store.getForPackage(packageName);
|
|
214
|
+
this.sendJson(res, 200, {
|
|
215
|
+
packageName,
|
|
216
|
+
count: entries.length,
|
|
217
|
+
certificates: entries.map(e => this.formatEntry(e)),
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
handleBadge(packageName, url, res) {
|
|
221
|
+
const style = (url.searchParams.get('style') ?? 'flat');
|
|
222
|
+
const entry = this.store.getLatestForPackage(packageName);
|
|
223
|
+
let svg;
|
|
224
|
+
if (!entry) {
|
|
225
|
+
svg = notFoundBadge(style);
|
|
226
|
+
}
|
|
227
|
+
else if (entry.verified) {
|
|
228
|
+
svg = gradeBadge(entry.grade, style);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
svg = verifiedBadge(false, style);
|
|
232
|
+
}
|
|
233
|
+
res.writeHead(200, {
|
|
234
|
+
'Content-Type': 'image/svg+xml',
|
|
235
|
+
'Cache-Control': 'max-age=300',
|
|
236
|
+
});
|
|
237
|
+
res.end(svg);
|
|
238
|
+
}
|
|
239
|
+
handleScoreBadge(packageName, url, res) {
|
|
240
|
+
const style = (url.searchParams.get('style') ?? 'flat');
|
|
241
|
+
const entry = this.store.getLatestForPackage(packageName);
|
|
242
|
+
let svg;
|
|
243
|
+
if (!entry) {
|
|
244
|
+
svg = notFoundBadge(style);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
svg = scoreBadge(entry.trustScore, style);
|
|
248
|
+
}
|
|
249
|
+
res.writeHead(200, {
|
|
250
|
+
'Content-Type': 'image/svg+xml',
|
|
251
|
+
'Cache-Control': 'max-age=300',
|
|
252
|
+
});
|
|
253
|
+
res.end(svg);
|
|
254
|
+
}
|
|
255
|
+
// ─── Helpers ───────────────────────────────────────────────────
|
|
256
|
+
formatEntry(entry) {
|
|
257
|
+
return {
|
|
258
|
+
id: entry.id,
|
|
259
|
+
packageName: entry.packageName,
|
|
260
|
+
packageVersion: entry.packageVersion,
|
|
261
|
+
trustScore: entry.trustScore,
|
|
262
|
+
grade: entry.grade,
|
|
263
|
+
verified: entry.verified,
|
|
264
|
+
registeredAt: entry.registeredAt,
|
|
265
|
+
issuerDid: entry.issuerDid,
|
|
266
|
+
certificate: entry.certificate,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
sendJson(res, status, data) {
|
|
270
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
271
|
+
res.end(JSON.stringify(data));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// ─── STC Validation ───────────────────────────────────────────────────
|
|
275
|
+
function validateSTC(cert) {
|
|
276
|
+
const errors = [];
|
|
277
|
+
if (!cert || typeof cert !== 'object') {
|
|
278
|
+
return ['Certificate must be a JSON object'];
|
|
279
|
+
}
|
|
280
|
+
// Required fields
|
|
281
|
+
if (!cert.id || typeof cert.id !== 'string')
|
|
282
|
+
errors.push('Missing or invalid "id" (string)');
|
|
283
|
+
if (cert.type !== 'SentinelTrustCertificate')
|
|
284
|
+
errors.push('"type" must be "SentinelTrustCertificate"');
|
|
285
|
+
if (cert['@context'] !== 'https://sentinel.trust/stc/v1')
|
|
286
|
+
errors.push('"@context" must be "https://sentinel.trust/stc/v1"');
|
|
287
|
+
// Timestamps
|
|
288
|
+
if (!cert.issuedAt || typeof cert.issuedAt !== 'string')
|
|
289
|
+
errors.push('Missing "issuedAt" (ISO date)');
|
|
290
|
+
if (!cert.expiresAt || typeof cert.expiresAt !== 'string')
|
|
291
|
+
errors.push('Missing "expiresAt" (ISO date)');
|
|
292
|
+
// Issuer
|
|
293
|
+
if (!cert.issuer || typeof cert.issuer !== 'object') {
|
|
294
|
+
errors.push('Missing "issuer" object');
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
if (!cert.issuer.did || typeof cert.issuer.did !== 'string')
|
|
298
|
+
errors.push('Missing "issuer.did"');
|
|
299
|
+
}
|
|
300
|
+
// Subject
|
|
301
|
+
if (!cert.subject || typeof cert.subject !== 'object') {
|
|
302
|
+
errors.push('Missing "subject" object');
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
if (!cert.subject.packageName || typeof cert.subject.packageName !== 'string')
|
|
306
|
+
errors.push('Missing "subject.packageName"');
|
|
307
|
+
if (!cert.subject.packageVersion || typeof cert.subject.packageVersion !== 'string')
|
|
308
|
+
errors.push('Missing "subject.packageVersion"');
|
|
309
|
+
}
|
|
310
|
+
// Trust score
|
|
311
|
+
if (!cert.trustScore || typeof cert.trustScore !== 'object') {
|
|
312
|
+
errors.push('Missing "trustScore" object');
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
if (typeof cert.trustScore.overall !== 'number' || cert.trustScore.overall < 0 || cert.trustScore.overall > 100) {
|
|
316
|
+
errors.push('"trustScore.overall" must be a number 0-100');
|
|
317
|
+
}
|
|
318
|
+
if (!cert.trustScore.grade || typeof cert.trustScore.grade !== 'string') {
|
|
319
|
+
errors.push('Missing "trustScore.grade"');
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// Proof
|
|
323
|
+
if (!cert.proof || typeof cert.proof !== 'object') {
|
|
324
|
+
errors.push('Missing "proof" object');
|
|
325
|
+
}
|
|
326
|
+
return errors;
|
|
327
|
+
}
|
|
328
|
+
// ─── Body Reader ──────────────────────────────────────────────────────
|
|
329
|
+
function readBody(req) {
|
|
330
|
+
return new Promise((resolve, reject) => {
|
|
331
|
+
const chunks = [];
|
|
332
|
+
let size = 0;
|
|
333
|
+
const MAX_BODY = 2_097_152; // 2 MB (STC max)
|
|
334
|
+
req.on('data', (chunk) => {
|
|
335
|
+
size += chunk.length;
|
|
336
|
+
if (size > MAX_BODY) {
|
|
337
|
+
reject(new Error('Request body too large'));
|
|
338
|
+
req.destroy();
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
chunks.push(chunk);
|
|
342
|
+
});
|
|
343
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString()));
|
|
344
|
+
req.on('error', reject);
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,gBAAgB,EAAsB,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAmB,MAAM,YAAY,CAAC;AACnG,OAAO,EACL,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EACvD,SAAS,EAAE,iBAAiB,EAC5B,kBAAkB,EAClB,oBAAoB,GAErB,MAAM,yBAAyB,CAAC;AAkBjC,wEAAwE;AAExE,MAAM,OAAO,cAAc;IACjB,MAAM,GAAkB,IAAI,CAAC;IAC7B,KAAK,CAAmB;IACxB,IAAI,CAAS;IACb,UAAU,CAAa;IACvB,UAAU,CAAa;IACvB,SAAS,CAAa;IAE9B,YAAY,OAA+B;QACzC,IAAI,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC;QAClC,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,IAAI,gBAAgB,EAAE,CAAC;QACtD,IAAI,CAAC,UAAU,GAAG,OAAO,EAAE,IAAI,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QAChE,IAAI,CAAC,UAAU,GAAG,OAAO,EAAE,IAAI,IAAI,iBAAiB,EAAE,CAAC;QACvD,IAAI,CAAC,SAAS,GAAG,OAAO,EAAE,GAAG,CAAC;QAE9B,wDAAwD;QACxD,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;YAC5D,IAAI,CAAC,UAAU,CAAC,WAAW,GAAG,CAAC,SAAS,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,qEAAqE;QACrE,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAExB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,MAAM,GAAG,kBAAkB,CAC9B,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,EAC1C,IAAI,CAAC,SAAS,CACf,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAChC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE;gBACjC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACrC,CAAC;iBAAM,CAAC;gBACN,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK;QACH,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC;IAC9D,CAAC;IAED,kEAAkE;IAE1D,KAAK,CAAC,aAAa,CAAC,GAAoB,EAAE,GAAmB;QACnE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC;QAC1B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC;QAEnC,8BAA8B;QAC9B,IAAI,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC;YAAE,OAAO,CAAC,oBAAoB;QAEtE,mBAAmB;QACnB,oBAAoB,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAElD,iBAAiB;QACjB,MAAM,UAAU,GAAG,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAEtD,uDAAuD;QACvD,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC5C,IAAI,CAAC,UAAU,CAAC,aAAa,IAAI,CAAC,WAAW,EAAE,CAAC;YAC9C,OAAO,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,CAAC;YACH,SAAS;YACT,IAAI,IAAI,KAAK,SAAS,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBAC3C,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACrF,CAAC;YAED,QAAQ;YACR,IAAI,IAAI,KAAK,eAAe,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACjD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxD,CAAC;YAED,8DAA8D;YAC9D,IAAI,IAAI,KAAK,sBAAsB,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACzD,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;oBAAE,OAAO,aAAa,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;gBACtF,OAAO,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC7C,CAAC;YAED,mCAAmC;YACnC,IAAI,IAAI,KAAK,sBAAsB,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACxD,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACpC,CAAC;YAED,sCAAsC;YACtC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;YAChE,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,EAAE,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5C,IAAI,MAAM,KAAK,KAAK;oBAAE,OAAO,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;gBACzD,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;oBACxB,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;wBAAE,OAAO,aAAa,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;oBACtF,OAAO,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;YAED,uEAAuE;YACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;YACnF,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,WAAW,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpD,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAEjC,IAAI,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK,KAAK;oBAAE,OAAO,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;gBACtF,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,KAAK;oBAAE,OAAO,IAAI,CAAC,oBAAoB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;gBAClG,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,KAAK;oBAAE,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC5F,IAAI,MAAM,KAAK,cAAc,IAAI,MAAM,KAAK,KAAK;oBAAE,OAAO,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YACzG,CAAC;YAED,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,kEAAkE;IAE1D,KAAK,CAAC,cAAc,CAAC,GAAoB,EAAE,GAAmB;QACpE,2BAA2B;QAC3B,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAChD,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC9D,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,uCAAuC,EAAE,CAAC,CAAC;QACrF,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,WAAqC,CAAC;QAE1C,IAAI,CAAC;YACH,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,+BAA+B;QAC/B,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;QACxC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,uBAAuB;QACvB,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,gCAAgC,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC;QAClG,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAErD,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;YACtB,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC,CAAC,CAAC;IACL,CAAC;IAEO,aAAa,CAAC,EAAU,EAAE,GAAmB;QACnD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IACnD,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,EAAU,EAAE,GAAmB;QACxD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IACjD,CAAC;IAEO,WAAW,CAAC,GAAQ,EAAE,GAAmB;QAC/C,MAAM,YAAY,GAAG,CAAC,GAAkB,EAAsB,EAAE;YAC9D,IAAI,GAAG,KAAK,IAAI;gBAAE,OAAO,SAAS,CAAC;YACnC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAC5B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC;QAEF,MAAM,CAAC,GAAG;YACR,WAAW,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,SAAS;YACzD,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACxD,QAAQ,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,SAAS;YACvD,QAAQ,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS;YACpG,KAAK,EAAE,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAClD,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;SACrD,CAAC;QAEF,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;YACtB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;YACzB,KAAK,EAAE,OAAO,CAAC,MAAM;YACrB,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;SACpD,CAAC,CAAC;IACL,CAAC;IAEO,gBAAgB,CAAC,WAAmB,EAAE,GAAmB;QAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAC1D,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,mCAAmC,EAAE,WAAW,EAAE,CAAC,CAAC;QAC9F,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IACnD,CAAC;IAEO,oBAAoB,CAAC,WAAmB,EAAE,GAAmB;QACnE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QACtD,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;YACtB,WAAW;YACX,KAAK,EAAE,OAAO,CAAC,MAAM;YACrB,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;SACpD,CAAC,CAAC;IACL,CAAC;IAEO,WAAW,CAAC,WAAmB,EAAE,GAAQ,EAAE,GAAmB;QACpE,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,MAAM,CAAe,CAAC;QACtE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAE1D,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;aAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC1B,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,GAAG,GAAG,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC;QAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YACjB,cAAc,EAAE,eAAe;YAC/B,eAAe,EAAE,aAAa;SAC/B,CAAC,CAAC;QACH,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACf,CAAC;IAEO,gBAAgB,CAAC,WAAmB,EAAE,GAAQ,EAAE,GAAmB;QACzE,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,MAAM,CAAe,CAAC;QACtE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAE1D,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC5C,CAAC;QAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YACjB,cAAc,EAAE,eAAe;YAC/B,eAAe,EAAE,aAAa;SAC/B,CAAC,CAAC;QACH,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACf,CAAC;IAED,kEAAkE;IAE1D,WAAW,CAAC,KAAoB;QACtC,OAAO;YACL,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAAC;IACJ,CAAC;IAEO,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;QACjE,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC9D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAChC,CAAC;CACF;AAED,yEAAyE;AAEzE,SAAS,WAAW,CAAC,IAAS;IAC5B,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,OAAO,CAAC,mCAAmC,CAAC,CAAC;IAC/C,CAAC;IAED,kBAAkB;IAClB,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IAC7F,IAAI,IAAI,CAAC,IAAI,KAAK,0BAA0B;QAAE,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IACvG,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,+BAA+B;QAAE,MAAM,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;IAE5H,aAAa;IACb,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;IACtG,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IAEzG,SAAS;IACT,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,QAAQ;YAAE,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACnG,CAAC;IAED,UAAU;IACV,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IAC1C,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,KAAK,QAAQ;YAAE,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC5H,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,KAAK,QAAQ;YAAE,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IACvI,CAAC;IAED,cAAc;IACd,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;QAC5D,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,IAAI,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC;YAChH,MAAM,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;QAC7D,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,IAAI,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxE,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,QAAQ;IACR,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAClD,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,yEAAyE;AAEzE,SAAS,QAAQ,CAAC,GAAoB;IACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,iBAAiB;QAE7C,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YAC/B,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC;YACrB,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC;gBACpB,MAAM,CAAC,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC;gBAC5C,GAAG,CAAC,OAAO,EAAE,CAAC;gBACd,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC/D,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Certificate Store — persistent storage for Sentinel Trust Certificates.
|
|
3
|
+
*
|
|
4
|
+
* Backed by SentinelStore interface — supports in-memory, Redis, Postgres, SQLite.
|
|
5
|
+
* By default uses in-memory Map for zero-config development.
|
|
6
|
+
*/
|
|
7
|
+
import { type SentinelTrustCertificate } from '@sentinel-atl/scanner';
|
|
8
|
+
import type { SentinelStore } from '@sentinel-atl/store';
|
|
9
|
+
export interface RegistryEntry {
|
|
10
|
+
/** STC ID */
|
|
11
|
+
id: string;
|
|
12
|
+
/** Full certificate */
|
|
13
|
+
certificate: SentinelTrustCertificate;
|
|
14
|
+
/** Package name (for lookup) */
|
|
15
|
+
packageName: string;
|
|
16
|
+
/** Package version */
|
|
17
|
+
packageVersion: string;
|
|
18
|
+
/** Trust score */
|
|
19
|
+
trustScore: number;
|
|
20
|
+
/** Grade */
|
|
21
|
+
grade: string;
|
|
22
|
+
/** Whether signature is verified */
|
|
23
|
+
verified: boolean;
|
|
24
|
+
/** When the entry was registered */
|
|
25
|
+
registeredAt: string;
|
|
26
|
+
/** Issuer DID */
|
|
27
|
+
issuerDid: string;
|
|
28
|
+
}
|
|
29
|
+
export interface RegistryQuery {
|
|
30
|
+
/** Filter by package name */
|
|
31
|
+
packageName?: string;
|
|
32
|
+
/** Filter by minimum trust score */
|
|
33
|
+
minScore?: number;
|
|
34
|
+
/** Filter by minimum grade */
|
|
35
|
+
minGrade?: string;
|
|
36
|
+
/** Filter by verified status */
|
|
37
|
+
verified?: boolean;
|
|
38
|
+
/** Maximum results */
|
|
39
|
+
limit?: number;
|
|
40
|
+
/** Offset for pagination */
|
|
41
|
+
offset?: number;
|
|
42
|
+
}
|
|
43
|
+
export interface RegistryStats {
|
|
44
|
+
totalCertificates: number;
|
|
45
|
+
verifiedCertificates: number;
|
|
46
|
+
uniquePackages: number;
|
|
47
|
+
averageScore: number;
|
|
48
|
+
gradeDistribution: Record<string, number>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Options for creating a CertificateStore.
|
|
52
|
+
* If `backend` is provided, certificates are persisted via SentinelStore.
|
|
53
|
+
* Otherwise, an in-memory Map is used (development only).
|
|
54
|
+
*/
|
|
55
|
+
export interface CertificateStoreOptions {
|
|
56
|
+
/** Persistent backend — data survives restarts */
|
|
57
|
+
backend?: SentinelStore;
|
|
58
|
+
/** Key prefix for the backend (default: 'registry:') */
|
|
59
|
+
prefix?: string;
|
|
60
|
+
}
|
|
61
|
+
export declare class CertificateStore {
|
|
62
|
+
private cache;
|
|
63
|
+
/** Index: packageName → entry IDs (newest first) */
|
|
64
|
+
private pkgIndex;
|
|
65
|
+
private backend?;
|
|
66
|
+
private prefix;
|
|
67
|
+
private loaded;
|
|
68
|
+
constructor(options?: CertificateStoreOptions);
|
|
69
|
+
/** Load all entries from the backend into the in-memory cache. Call once on startup. */
|
|
70
|
+
load(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Register a new certificate. Verifies signature before storing.
|
|
73
|
+
*/
|
|
74
|
+
register(certificate: SentinelTrustCertificate): Promise<RegistryEntry>;
|
|
75
|
+
/**
|
|
76
|
+
* Get a certificate by ID.
|
|
77
|
+
*/
|
|
78
|
+
get(id: string): RegistryEntry | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Get the latest certificate for a package.
|
|
81
|
+
*/
|
|
82
|
+
getLatestForPackage(packageName: string): RegistryEntry | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* Get all certificates for a package.
|
|
85
|
+
*/
|
|
86
|
+
getForPackage(packageName: string): RegistryEntry[];
|
|
87
|
+
/**
|
|
88
|
+
* Query certificates with filters.
|
|
89
|
+
*/
|
|
90
|
+
query(q: RegistryQuery): RegistryEntry[];
|
|
91
|
+
/**
|
|
92
|
+
* Remove a certificate by ID.
|
|
93
|
+
*/
|
|
94
|
+
remove(id: string): Promise<boolean>;
|
|
95
|
+
/**
|
|
96
|
+
* Get registry statistics.
|
|
97
|
+
*/
|
|
98
|
+
getStats(): RegistryStats;
|
|
99
|
+
/**
|
|
100
|
+
* Get total count (for pagination).
|
|
101
|
+
*/
|
|
102
|
+
count(): number;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAa,KAAK,wBAAwB,EAAwB,MAAM,uBAAuB,CAAC;AACvG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD,MAAM,WAAW,aAAa;IAC5B,aAAa;IACb,EAAE,EAAE,MAAM,CAAC;IACX,uBAAuB;IACvB,WAAW,EAAE,wBAAwB,CAAC;IACtC,gCAAgC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,QAAQ,EAAE,OAAO,CAAC;IAClB,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAYD;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,kDAAkD;IAClD,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAMD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,KAAK,CAAoC;IACjD,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,OAAO,CAAC,CAAgB;IAChC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,CAAC,EAAE,uBAAuB;IAK7C,wFAAwF;IAClF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB3B;;OAEG;IACG,QAAQ,CAAC,WAAW,EAAE,wBAAwB,GAAG,OAAO,CAAC,aAAa,CAAC;IAkC7E;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI1C;;OAEG;IACH,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAMnE;;OAEG;IACH,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE;IAKnD;;OAEG;IACH,KAAK,CAAC,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE;IAwBxC;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA6B1C;;OAEG;IACH,QAAQ,IAAI,aAAa;IAmBzB;;OAEG;IACH,KAAK,IAAI,MAAM;CAGhB"}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Certificate Store — persistent storage for Sentinel Trust Certificates.
|
|
3
|
+
*
|
|
4
|
+
* Backed by SentinelStore interface — supports in-memory, Redis, Postgres, SQLite.
|
|
5
|
+
* By default uses in-memory Map for zero-config development.
|
|
6
|
+
*/
|
|
7
|
+
import { verifySTC } from '@sentinel-atl/scanner';
|
|
8
|
+
// ─── Grade Helpers ───────────────────────────────────────────────────
|
|
9
|
+
const GRADE_ORDER = { A: 4, B: 3, C: 2, D: 1, F: 0 };
|
|
10
|
+
function gradeAtLeast(actual, required) {
|
|
11
|
+
return (GRADE_ORDER[actual] ?? 0) >= (GRADE_ORDER[required] ?? 0);
|
|
12
|
+
}
|
|
13
|
+
const KEY_PREFIX_DEFAULT = 'registry:';
|
|
14
|
+
const CERT_PREFIX = 'cert:';
|
|
15
|
+
const PKG_INDEX_PREFIX = 'pkg:';
|
|
16
|
+
export class CertificateStore {
|
|
17
|
+
cache = new Map();
|
|
18
|
+
/** Index: packageName → entry IDs (newest first) */
|
|
19
|
+
pkgIndex = new Map();
|
|
20
|
+
backend;
|
|
21
|
+
prefix;
|
|
22
|
+
loaded = false;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.backend = options?.backend;
|
|
25
|
+
this.prefix = options?.prefix ?? KEY_PREFIX_DEFAULT;
|
|
26
|
+
}
|
|
27
|
+
/** Load all entries from the backend into the in-memory cache. Call once on startup. */
|
|
28
|
+
async load() {
|
|
29
|
+
if (this.loaded || !this.backend)
|
|
30
|
+
return;
|
|
31
|
+
const keys = await this.backend.keys(`${this.prefix}${CERT_PREFIX}`);
|
|
32
|
+
const values = await this.backend.getMany(keys);
|
|
33
|
+
for (const [, json] of values) {
|
|
34
|
+
const entry = JSON.parse(json);
|
|
35
|
+
this.cache.set(entry.id, entry);
|
|
36
|
+
const existing = this.pkgIndex.get(entry.packageName) ?? [];
|
|
37
|
+
existing.push(entry.id);
|
|
38
|
+
this.pkgIndex.set(entry.packageName, existing);
|
|
39
|
+
}
|
|
40
|
+
// Sort each package's IDs by registeredAt descending
|
|
41
|
+
for (const [pkg, ids] of this.pkgIndex) {
|
|
42
|
+
ids.sort((a, b) => {
|
|
43
|
+
const ea = this.cache.get(a);
|
|
44
|
+
const eb = this.cache.get(b);
|
|
45
|
+
return eb.registeredAt.localeCompare(ea.registeredAt);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
this.loaded = true;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Register a new certificate. Verifies signature before storing.
|
|
52
|
+
*/
|
|
53
|
+
async register(certificate) {
|
|
54
|
+
const result = await verifySTC(certificate);
|
|
55
|
+
const entry = {
|
|
56
|
+
id: certificate.id,
|
|
57
|
+
certificate,
|
|
58
|
+
packageName: certificate.subject.packageName,
|
|
59
|
+
packageVersion: certificate.subject.packageVersion,
|
|
60
|
+
trustScore: certificate.trustScore.overall,
|
|
61
|
+
grade: certificate.trustScore.grade,
|
|
62
|
+
verified: result.valid,
|
|
63
|
+
registeredAt: new Date().toISOString(),
|
|
64
|
+
issuerDid: certificate.issuer.did,
|
|
65
|
+
};
|
|
66
|
+
this.cache.set(entry.id, entry);
|
|
67
|
+
// Update package index
|
|
68
|
+
const existing = this.pkgIndex.get(entry.packageName) ?? [];
|
|
69
|
+
existing.unshift(entry.id); // newest first
|
|
70
|
+
this.pkgIndex.set(entry.packageName, existing);
|
|
71
|
+
// Persist to backend
|
|
72
|
+
if (this.backend) {
|
|
73
|
+
await this.backend.set(`${this.prefix}${CERT_PREFIX}${entry.id}`, JSON.stringify(entry));
|
|
74
|
+
await this.backend.set(`${this.prefix}${PKG_INDEX_PREFIX}${entry.packageName}`, JSON.stringify(existing));
|
|
75
|
+
}
|
|
76
|
+
return entry;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get a certificate by ID.
|
|
80
|
+
*/
|
|
81
|
+
get(id) {
|
|
82
|
+
return this.cache.get(id);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get the latest certificate for a package.
|
|
86
|
+
*/
|
|
87
|
+
getLatestForPackage(packageName) {
|
|
88
|
+
const ids = this.pkgIndex.get(packageName);
|
|
89
|
+
if (!ids || ids.length === 0)
|
|
90
|
+
return undefined;
|
|
91
|
+
return this.cache.get(ids[0]);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get all certificates for a package.
|
|
95
|
+
*/
|
|
96
|
+
getForPackage(packageName) {
|
|
97
|
+
const ids = this.pkgIndex.get(packageName) ?? [];
|
|
98
|
+
return ids.map(id => this.cache.get(id)).filter(Boolean);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Query certificates with filters.
|
|
102
|
+
*/
|
|
103
|
+
query(q) {
|
|
104
|
+
let results = Array.from(this.cache.values());
|
|
105
|
+
if (q.packageName) {
|
|
106
|
+
results = results.filter(e => e.packageName === q.packageName);
|
|
107
|
+
}
|
|
108
|
+
if (q.minScore !== undefined) {
|
|
109
|
+
results = results.filter(e => e.trustScore >= q.minScore);
|
|
110
|
+
}
|
|
111
|
+
if (q.minGrade) {
|
|
112
|
+
results = results.filter(e => gradeAtLeast(e.grade, q.minGrade));
|
|
113
|
+
}
|
|
114
|
+
if (q.verified !== undefined) {
|
|
115
|
+
results = results.filter(e => e.verified === q.verified);
|
|
116
|
+
}
|
|
117
|
+
// Sort by registeredAt descending
|
|
118
|
+
results.sort((a, b) => b.registeredAt.localeCompare(a.registeredAt));
|
|
119
|
+
const offset = q.offset ?? 0;
|
|
120
|
+
const limit = q.limit ?? 50;
|
|
121
|
+
return results.slice(offset, offset + limit);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Remove a certificate by ID.
|
|
125
|
+
*/
|
|
126
|
+
async remove(id) {
|
|
127
|
+
const entry = this.cache.get(id);
|
|
128
|
+
if (!entry)
|
|
129
|
+
return false;
|
|
130
|
+
this.cache.delete(id);
|
|
131
|
+
const ids = this.pkgIndex.get(entry.packageName);
|
|
132
|
+
if (ids) {
|
|
133
|
+
const idx = ids.indexOf(id);
|
|
134
|
+
if (idx !== -1)
|
|
135
|
+
ids.splice(idx, 1);
|
|
136
|
+
if (ids.length === 0)
|
|
137
|
+
this.pkgIndex.delete(entry.packageName);
|
|
138
|
+
}
|
|
139
|
+
// Persist deletion to backend
|
|
140
|
+
if (this.backend) {
|
|
141
|
+
await this.backend.delete(`${this.prefix}${CERT_PREFIX}${id}`);
|
|
142
|
+
if (ids && ids.length > 0) {
|
|
143
|
+
await this.backend.set(`${this.prefix}${PKG_INDEX_PREFIX}${entry.packageName}`, JSON.stringify(ids));
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
await this.backend.delete(`${this.prefix}${PKG_INDEX_PREFIX}${entry.packageName}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Get registry statistics.
|
|
153
|
+
*/
|
|
154
|
+
getStats() {
|
|
155
|
+
const all = Array.from(this.cache.values());
|
|
156
|
+
const gradeDistribution = { A: 0, B: 0, C: 0, D: 0, F: 0 };
|
|
157
|
+
let totalScore = 0;
|
|
158
|
+
for (const entry of all) {
|
|
159
|
+
totalScore += entry.trustScore;
|
|
160
|
+
gradeDistribution[entry.grade] = (gradeDistribution[entry.grade] ?? 0) + 1;
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
totalCertificates: all.length,
|
|
164
|
+
verifiedCertificates: all.filter(e => e.verified).length,
|
|
165
|
+
uniquePackages: this.pkgIndex.size,
|
|
166
|
+
averageScore: all.length > 0 ? Math.round(totalScore / all.length) : 0,
|
|
167
|
+
gradeDistribution,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get total count (for pagination).
|
|
172
|
+
*/
|
|
173
|
+
count() {
|
|
174
|
+
return this.cache.size;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|