@zincapp/znvault-cli 2.19.0 → 2.19.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/dist/commands/dynamic-secrets/connection.d.ts +17 -0
- package/dist/commands/dynamic-secrets/connection.d.ts.map +1 -0
- package/dist/commands/dynamic-secrets/connection.js +217 -0
- package/dist/commands/dynamic-secrets/connection.js.map +1 -0
- package/dist/commands/dynamic-secrets/creds.d.ts +5 -0
- package/dist/commands/dynamic-secrets/creds.d.ts.map +1 -0
- package/dist/commands/dynamic-secrets/creds.js +39 -0
- package/dist/commands/dynamic-secrets/creds.js.map +1 -0
- package/dist/commands/dynamic-secrets/helpers.d.ts +5 -0
- package/dist/commands/dynamic-secrets/helpers.d.ts.map +1 -0
- package/dist/commands/dynamic-secrets/helpers.js +36 -0
- package/dist/commands/dynamic-secrets/helpers.js.map +1 -0
- package/dist/commands/dynamic-secrets/index.d.ts +7 -0
- package/dist/commands/dynamic-secrets/index.d.ts.map +1 -0
- package/dist/commands/dynamic-secrets/index.js +173 -0
- package/dist/commands/dynamic-secrets/index.js.map +1 -0
- package/dist/commands/dynamic-secrets/lease.d.ts +11 -0
- package/dist/commands/dynamic-secrets/lease.d.ts.map +1 -0
- package/dist/commands/dynamic-secrets/lease.js +137 -0
- package/dist/commands/dynamic-secrets/lease.js.map +1 -0
- package/dist/commands/dynamic-secrets/role.d.ts +15 -0
- package/dist/commands/dynamic-secrets/role.d.ts.map +1 -0
- package/dist/commands/dynamic-secrets/role.js +184 -0
- package/dist/commands/dynamic-secrets/role.js.map +1 -0
- package/dist/commands/dynamic-secrets/types.d.ts +125 -0
- package/dist/commands/dynamic-secrets/types.d.ts.map +1 -0
- package/dist/commands/dynamic-secrets/types.js +3 -0
- package/dist/commands/dynamic-secrets/types.js.map +1 -0
- package/dist/commands/dynamic-secrets.d.ts +6 -2
- package/dist/commands/dynamic-secrets.d.ts.map +1 -1
- package/dist/commands/dynamic-secrets.js +6 -754
- package/dist/commands/dynamic-secrets.js.map +1 -1
- package/dist/commands/policy/attachments.d.ts +9 -0
- package/dist/commands/policy/attachments.d.ts.map +1 -0
- package/dist/commands/policy/attachments.js +161 -0
- package/dist/commands/policy/attachments.js.map +1 -0
- package/dist/commands/policy/crud.d.ts +8 -0
- package/dist/commands/policy/crud.d.ts.map +1 -0
- package/dist/commands/policy/crud.js +232 -0
- package/dist/commands/policy/crud.js.map +1 -0
- package/dist/commands/policy/helpers.d.ts +13 -0
- package/dist/commands/policy/helpers.d.ts.map +1 -0
- package/dist/commands/policy/helpers.js +61 -0
- package/dist/commands/policy/helpers.js.map +1 -0
- package/dist/commands/policy/index.d.ts +7 -0
- package/dist/commands/policy/index.d.ts.map +1 -0
- package/dist/commands/policy/index.js +160 -0
- package/dist/commands/policy/index.js.map +1 -0
- package/dist/commands/policy/io.d.ts +4 -0
- package/dist/commands/policy/io.d.ts.map +1 -0
- package/dist/commands/policy/io.js +65 -0
- package/dist/commands/policy/io.js.map +1 -0
- package/dist/commands/policy/list.d.ts +4 -0
- package/dist/commands/policy/list.d.ts.map +1 -0
- package/dist/commands/policy/list.js +99 -0
- package/dist/commands/policy/list.js.map +1 -0
- package/dist/commands/policy/test.d.ts +3 -0
- package/dist/commands/policy/test.d.ts.map +1 -0
- package/dist/commands/policy/test.js +58 -0
- package/dist/commands/policy/test.js.map +1 -0
- package/dist/commands/policy/types.d.ts +84 -0
- package/dist/commands/policy/types.d.ts.map +1 -0
- package/dist/commands/policy/types.js +3 -0
- package/dist/commands/policy/types.js.map +1 -0
- package/dist/commands/policy.d.ts +6 -2
- package/dist/commands/policy.d.ts.map +1 -1
- package/dist/commands/policy.js +4 -770
- package/dist/commands/policy.js.map +1 -1
- package/dist/lib/db/audit.d.ts +16 -0
- package/dist/lib/db/audit.d.ts.map +1 -0
- package/dist/lib/db/audit.js +60 -0
- package/dist/lib/db/audit.js.map +1 -0
- package/dist/lib/db/client.d.ts +27 -0
- package/dist/lib/db/client.d.ts.map +1 -0
- package/dist/lib/db/client.js +70 -0
- package/dist/lib/db/client.js.map +1 -0
- package/dist/lib/db/emergency.d.ts +50 -0
- package/dist/lib/db/emergency.d.ts.map +1 -0
- package/dist/lib/db/emergency.js +180 -0
- package/dist/lib/db/emergency.js.map +1 -0
- package/dist/lib/db/health.d.ts +14 -0
- package/dist/lib/db/health.d.ts.map +1 -0
- package/dist/lib/db/health.js +177 -0
- package/dist/lib/db/health.js.map +1 -0
- package/dist/lib/db/index.d.ts +56 -0
- package/dist/lib/db/index.d.ts.map +1 -0
- package/dist/lib/db/index.js +107 -0
- package/dist/lib/db/index.js.map +1 -0
- package/dist/lib/db/lockdown.d.ts +15 -0
- package/dist/lib/db/lockdown.d.ts.map +1 -0
- package/dist/lib/db/lockdown.js +67 -0
- package/dist/lib/db/lockdown.js.map +1 -0
- package/dist/lib/db/tenants.d.ts +14 -0
- package/dist/lib/db/tenants.d.ts.map +1 -0
- package/dist/lib/db/tenants.js +88 -0
- package/dist/lib/db/tenants.js.map +1 -0
- package/dist/lib/db/types.d.ts +95 -0
- package/dist/lib/db/types.d.ts.map +1 -0
- package/dist/lib/db/types.js +3 -0
- package/dist/lib/db/types.js.map +1 -0
- package/dist/lib/db/users.d.ts +16 -0
- package/dist/lib/db/users.d.ts.map +1 -0
- package/dist/lib/db/users.js +95 -0
- package/dist/lib/db/users.js.map +1 -0
- package/dist/lib/db.d.ts +4 -112
- package/dist/lib/db.d.ts.map +1 -1
- package/dist/lib/db.js +4 -726
- package/dist/lib/db.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// Path: src/lib/db/health.ts
|
|
2
|
+
import { REDIS_PING_TIMEOUT_MS, REDIS_SENTINEL_TIMEOUT_MS } from '../constants.js';
|
|
3
|
+
import { BaseDBClient } from './client.js';
|
|
4
|
+
export class HealthOperations extends BaseDBClient {
|
|
5
|
+
async health() {
|
|
6
|
+
await this.connect();
|
|
7
|
+
const dbTime = await this.queryOne('SELECT NOW() as now');
|
|
8
|
+
const version = await this.getVaultVersion();
|
|
9
|
+
const haEnabled = process.env.HA_ENABLED === 'true';
|
|
10
|
+
const nodeId = process.env.HA_NODE_ID ?? 'standalone';
|
|
11
|
+
const pgStatus = await this.getPostgresStatus();
|
|
12
|
+
const redisStatus = await this.getRedisStatus();
|
|
13
|
+
let clusterSize = 1;
|
|
14
|
+
let isLeader = false;
|
|
15
|
+
if (haEnabled && redisStatus.status === 'ok') {
|
|
16
|
+
const clusterInfo = await this.getClusterInfoFromRedis();
|
|
17
|
+
clusterSize = clusterInfo.nodeCount;
|
|
18
|
+
isLeader = clusterInfo.leaderNodeId === nodeId;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
status: 'ok',
|
|
22
|
+
version,
|
|
23
|
+
uptime: process.uptime(),
|
|
24
|
+
timestamp: dbTime?.now.toISOString() ?? new Date().toISOString(),
|
|
25
|
+
database: pgStatus,
|
|
26
|
+
redis: redisStatus.status !== 'unavailable' ? redisStatus : undefined,
|
|
27
|
+
ha: haEnabled ? {
|
|
28
|
+
enabled: true,
|
|
29
|
+
nodeId,
|
|
30
|
+
isLeader,
|
|
31
|
+
clusterSize,
|
|
32
|
+
} : undefined,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async clusterStatus() {
|
|
36
|
+
await this.connect();
|
|
37
|
+
const haEnabled = process.env.HA_ENABLED === 'true';
|
|
38
|
+
const nodeId = process.env.HA_NODE_ID ?? 'unknown';
|
|
39
|
+
let nodes = [];
|
|
40
|
+
try {
|
|
41
|
+
const dbNodes = await this.query(`
|
|
42
|
+
SELECT node_id, advertised_host, advertised_port, is_leader, last_heartbeat, status
|
|
43
|
+
FROM ha_nodes
|
|
44
|
+
ORDER BY node_id
|
|
45
|
+
`);
|
|
46
|
+
nodes = dbNodes.map(n => ({
|
|
47
|
+
nodeId: n.node_id,
|
|
48
|
+
host: n.advertised_host,
|
|
49
|
+
port: n.advertised_port,
|
|
50
|
+
isLeader: n.is_leader,
|
|
51
|
+
isHealthy: n.status === 'healthy',
|
|
52
|
+
lastHeartbeat: n.last_heartbeat.toISOString(),
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Table might not exist in non-HA setups
|
|
57
|
+
}
|
|
58
|
+
const leader = nodes.find(n => n.isLeader);
|
|
59
|
+
return {
|
|
60
|
+
enabled: haEnabled,
|
|
61
|
+
nodeId,
|
|
62
|
+
isLeader: leader?.nodeId === nodeId,
|
|
63
|
+
leaderNodeId: leader?.nodeId ?? null,
|
|
64
|
+
nodes,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async getVaultVersion() {
|
|
68
|
+
try {
|
|
69
|
+
const fs = await import('node:fs');
|
|
70
|
+
const manifestPaths = [
|
|
71
|
+
'/opt/znvault/current/MANIFEST.json',
|
|
72
|
+
'/opt/znvault/current/manifest.json',
|
|
73
|
+
];
|
|
74
|
+
for (const manifestPath of manifestPaths) {
|
|
75
|
+
if (fs.existsSync(manifestPath)) {
|
|
76
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
77
|
+
return manifest.version ?? '1.2.9';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Ignore
|
|
83
|
+
}
|
|
84
|
+
return process.env.npm_package_version ?? '1.2.9';
|
|
85
|
+
}
|
|
86
|
+
async getPostgresStatus() {
|
|
87
|
+
try {
|
|
88
|
+
const recovery = await this.queryOne('SELECT pg_is_in_recovery() as in_recovery');
|
|
89
|
+
if (recovery?.in_recovery) {
|
|
90
|
+
const lag = await this.queryOne("SELECT pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn()) as lag_bytes");
|
|
91
|
+
return {
|
|
92
|
+
status: 'ok',
|
|
93
|
+
role: 'replica',
|
|
94
|
+
replicationLag: lag ? parseInt(lag.lag_bytes, 10) : 0,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const replicas = await this.query('SELECT client_addr, state FROM pg_stat_replication');
|
|
98
|
+
return {
|
|
99
|
+
status: 'ok',
|
|
100
|
+
role: 'primary',
|
|
101
|
+
replicationLag: replicas.length > 0 ? 0 : undefined,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return { status: 'ok' };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async getRedisStatus() {
|
|
109
|
+
const sentinelNodes = process.env.REDIS_SENTINEL_NODES;
|
|
110
|
+
const sentinelMaster = process.env.REDIS_SENTINEL_MASTER ?? 'znvault-master';
|
|
111
|
+
if (!sentinelNodes) {
|
|
112
|
+
if (process.env.REDIS_URL) {
|
|
113
|
+
try {
|
|
114
|
+
const result = await this.execAsync(`redis-cli -u "${process.env.REDIS_URL}" PING 2>/dev/null`, REDIS_PING_TIMEOUT_MS);
|
|
115
|
+
return { status: result.trim() === 'PONG' ? 'ok' : 'error' };
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return { status: 'error' };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return { status: 'unavailable' };
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
const nodes = sentinelNodes.split(',');
|
|
125
|
+
const nodeResults = await Promise.allSettled(nodes.map(async (node) => {
|
|
126
|
+
const [host, port] = node.split(':');
|
|
127
|
+
const result = await this.execAsync(`redis-cli -h ${host} -p ${port} SENTINEL get-master-addr-by-name ${sentinelMaster} 2>/dev/null`, REDIS_SENTINEL_TIMEOUT_MS);
|
|
128
|
+
return result.trim();
|
|
129
|
+
}));
|
|
130
|
+
let healthyNodes = 0;
|
|
131
|
+
let masterHost = '';
|
|
132
|
+
for (const result of nodeResults) {
|
|
133
|
+
if (result.status === 'fulfilled' && result.value) {
|
|
134
|
+
healthyNodes++;
|
|
135
|
+
if (!masterHost) {
|
|
136
|
+
const lines = result.value.split('\n');
|
|
137
|
+
masterHost = lines[0] ?? '';
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
status: healthyNodes >= 2 ? 'ok' : (healthyNodes > 0 ? 'degraded' : 'error'),
|
|
143
|
+
sentinelNodes: healthyNodes,
|
|
144
|
+
master: masterHost || undefined,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return { status: 'error' };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async getClusterInfoFromRedis() {
|
|
152
|
+
const sentinelNodes = process.env.REDIS_SENTINEL_NODES;
|
|
153
|
+
const sentinelMaster = process.env.REDIS_SENTINEL_MASTER ?? 'znvault-master';
|
|
154
|
+
if (!sentinelNodes) {
|
|
155
|
+
return { nodeCount: 1, leaderNodeId: null };
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const nodes = sentinelNodes.split(',');
|
|
159
|
+
const [host, port] = nodes[0].split(':');
|
|
160
|
+
const masterResult = await this.execAsync(`redis-cli -h ${host} -p ${port} SENTINEL get-master-addr-by-name ${sentinelMaster} 2>/dev/null`, 3000);
|
|
161
|
+
const masterHost = masterResult.trim().split('\n')[0];
|
|
162
|
+
const masterPort = masterResult.trim().split('\n')[1] ?? '6379';
|
|
163
|
+
const [nodesResult, leaderResult] = await Promise.all([
|
|
164
|
+
this.execAsync(`redis-cli -h ${masterHost} -p ${masterPort} HGETALL 'zn-vault:nodes' 2>/dev/null`, 3000),
|
|
165
|
+
this.execAsync(`redis-cli -h ${masterHost} -p ${masterPort} GET 'zn-vault:leader' 2>/dev/null`, 3000),
|
|
166
|
+
]);
|
|
167
|
+
const lines = nodesResult.trim().split('\n').filter(l => l);
|
|
168
|
+
const nodeCount = Math.max(Math.floor(lines.length / 2), 1);
|
|
169
|
+
const leaderNodeId = leaderResult.trim() || null;
|
|
170
|
+
return { nodeCount, leaderNodeId };
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return { nodeCount: 3, leaderNodeId: null };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../../src/lib/db/health.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { TenantOperations } from './tenants.js';
|
|
2
|
+
import { UserOperations } from './users.js';
|
|
3
|
+
import { LockdownOperations } from './lockdown.js';
|
|
4
|
+
import { AuditOperations } from './audit.js';
|
|
5
|
+
export * from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Composite database client that combines all operation modules.
|
|
8
|
+
* Uses composition pattern to delegate to specialized operation classes.
|
|
9
|
+
*/
|
|
10
|
+
export declare class LocalDBClient {
|
|
11
|
+
private healthOps;
|
|
12
|
+
private tenantOps;
|
|
13
|
+
private userOps;
|
|
14
|
+
private lockdownOps;
|
|
15
|
+
private auditOps;
|
|
16
|
+
private emergencyOps;
|
|
17
|
+
constructor();
|
|
18
|
+
connect(): Promise<void>;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
disconnect(): Promise<void>;
|
|
21
|
+
health: () => Promise<import("../../types/index.js").HealthResponse>;
|
|
22
|
+
clusterStatus: () => Promise<import("../../types/index.js").ClusterStatus>;
|
|
23
|
+
listTenants: (options?: Parameters<TenantOperations["listTenants"]>[0]) => Promise<import("../../types/index.js").TenantWithUsage[]>;
|
|
24
|
+
getTenant: (id: string, withUsage?: boolean) => Promise<import("../../types/index.js").TenantWithUsage | null>;
|
|
25
|
+
getTenantUsage: (id: string) => Promise<import("../../types/index.js").TenantUsage>;
|
|
26
|
+
listUsers: (options?: Parameters<UserOperations["listUsers"]>[0]) => Promise<import("../../types/index.js").User[]>;
|
|
27
|
+
getUser: (id: string) => Promise<import("../../types/index.js").User | null>;
|
|
28
|
+
getUserByUsername: (username: string) => Promise<import("../../types/index.js").User | null>;
|
|
29
|
+
listSuperadmins: () => Promise<import("../../types/index.js").Superadmin[]>;
|
|
30
|
+
getLockdownStatus: () => Promise<import("../../types/index.js").LockdownStatus>;
|
|
31
|
+
getLockdownHistory: (limit?: number) => Promise<import("../../types/index.js").LockdownHistoryEntry[]>;
|
|
32
|
+
getThreats: (options?: Parameters<LockdownOperations["getThreats"]>[0]) => Promise<import("../../types/index.js").ThreatEvent[]>;
|
|
33
|
+
listAudit: (options?: Parameters<AuditOperations["listAudit"]>[0]) => Promise<import("../../types/index.js").AuditEntry[]>;
|
|
34
|
+
verifyAuditChain: () => Promise<import("../../types/index.js").AuditVerifyResult>;
|
|
35
|
+
testConnection: () => Promise<import("./emergency.js").ConnectionTestResult>;
|
|
36
|
+
getUserStatus: (username: string) => Promise<import("./emergency.js").UserStatusResult>;
|
|
37
|
+
resetPassword: (username: string, newPassword: string) => Promise<import("./emergency.js").OperationResult>;
|
|
38
|
+
unlockUser: (username: string) => Promise<import("./emergency.js").OperationResult>;
|
|
39
|
+
disableTotp: (username: string) => Promise<import("./emergency.js").OperationResult>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Legacy EmergencyDBClient class (alias for LocalDBClient)
|
|
43
|
+
* @deprecated Use LocalDBClient instead
|
|
44
|
+
*/
|
|
45
|
+
export declare class EmergencyDBClient extends LocalDBClient {
|
|
46
|
+
constructor();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Check if emergency DB access is available
|
|
50
|
+
*/
|
|
51
|
+
export declare function isEmergencyDbAvailable(): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Check if local mode is available (more comprehensive check)
|
|
54
|
+
*/
|
|
55
|
+
export declare function isLocalDbAvailable(): boolean;
|
|
56
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/db/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAI7C,cAAc,YAAY,CAAC;AAE3B;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,YAAY,CAAsB;;IAapC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAKjC,MAAM,+DAAiC;IACvC,aAAa,8DAAwC;IAGrD,WAAW,GAAI,UAAU,UAAU,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,+DACjC;IACtC,SAAS,GAAI,IAAI,MAAM,EAAE,YAAY,OAAO,oEACF;IAC1C,cAAc,GAAI,IAAI,MAAM,yDACQ;IAGpC,SAAS,GAAI,UAAU,UAAU,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,oDAC/B;IAClC,OAAO,GAAI,IAAI,MAAM,yDACM;IAC3B,iBAAiB,GAAI,UAAU,MAAM,yDACM;IAC3C,eAAe,6DACkB;IAGjC,iBAAiB,+DACsB;IACvC,kBAAkB,GAAI,QAAQ,MAAM,oEACS;IAC7C,UAAU,GAAI,UAAU,UAAU,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,2DAChC;IAGvC,SAAS,GAAI,UAAU,UAAU,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,0DAC/B;IACnC,gBAAgB,kEACmB;IAGnC,cAAc,+DACuB;IACrC,aAAa,GAAI,UAAU,MAAM,wDACW;IAC5C,aAAa,GAAI,UAAU,MAAM,EAAE,aAAa,MAAM,uDACG;IACzD,UAAU,GAAI,UAAU,MAAM,uDACW;IACzC,WAAW,GAAI,UAAU,MAAM,uDACW;CAC3C;AAID;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,aAAa;;CAWnD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAG5C"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Path: src/lib/db/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Modular database client for direct PostgreSQL operations.
|
|
4
|
+
* Used for local mode (running on vault nodes) and emergency operations.
|
|
5
|
+
*/
|
|
6
|
+
import { getLocalConfig } from '../local.js';
|
|
7
|
+
import { HealthOperations } from './health.js';
|
|
8
|
+
import { TenantOperations } from './tenants.js';
|
|
9
|
+
import { UserOperations } from './users.js';
|
|
10
|
+
import { LockdownOperations } from './lockdown.js';
|
|
11
|
+
import { AuditOperations } from './audit.js';
|
|
12
|
+
import { EmergencyOperations } from './emergency.js';
|
|
13
|
+
// Re-export types
|
|
14
|
+
export * from './types.js';
|
|
15
|
+
/**
|
|
16
|
+
* Composite database client that combines all operation modules.
|
|
17
|
+
* Uses composition pattern to delegate to specialized operation classes.
|
|
18
|
+
*/
|
|
19
|
+
export class LocalDBClient {
|
|
20
|
+
healthOps;
|
|
21
|
+
tenantOps;
|
|
22
|
+
userOps;
|
|
23
|
+
lockdownOps;
|
|
24
|
+
auditOps;
|
|
25
|
+
emergencyOps;
|
|
26
|
+
constructor() {
|
|
27
|
+
// All operations share the same connection strategy via BaseDBClient
|
|
28
|
+
this.healthOps = new HealthOperations();
|
|
29
|
+
this.tenantOps = new TenantOperations();
|
|
30
|
+
this.userOps = new UserOperations();
|
|
31
|
+
this.lockdownOps = new LockdownOperations();
|
|
32
|
+
this.auditOps = new AuditOperations();
|
|
33
|
+
this.emergencyOps = new EmergencyOperations();
|
|
34
|
+
}
|
|
35
|
+
// Connection management - delegate to health ops (or any op, they all have the same base)
|
|
36
|
+
async connect() {
|
|
37
|
+
await this.healthOps.connect();
|
|
38
|
+
}
|
|
39
|
+
async close() {
|
|
40
|
+
// Close all connections
|
|
41
|
+
await Promise.all([
|
|
42
|
+
this.healthOps.close(),
|
|
43
|
+
this.tenantOps.close(),
|
|
44
|
+
this.userOps.close(),
|
|
45
|
+
this.lockdownOps.close(),
|
|
46
|
+
this.auditOps.close(),
|
|
47
|
+
this.emergencyOps.close(),
|
|
48
|
+
]);
|
|
49
|
+
}
|
|
50
|
+
async disconnect() {
|
|
51
|
+
return this.close();
|
|
52
|
+
}
|
|
53
|
+
// ============ Health ============
|
|
54
|
+
health = () => this.healthOps.health();
|
|
55
|
+
clusterStatus = () => this.healthOps.clusterStatus();
|
|
56
|
+
// ============ Tenants ============
|
|
57
|
+
listTenants = (options) => this.tenantOps.listTenants(options);
|
|
58
|
+
getTenant = (id, withUsage) => this.tenantOps.getTenant(id, withUsage);
|
|
59
|
+
getTenantUsage = (id) => this.tenantOps.getTenantUsage(id);
|
|
60
|
+
// ============ Users ============
|
|
61
|
+
listUsers = (options) => this.userOps.listUsers(options);
|
|
62
|
+
getUser = (id) => this.userOps.getUser(id);
|
|
63
|
+
getUserByUsername = (username) => this.userOps.getUserByUsername(username);
|
|
64
|
+
listSuperadmins = () => this.userOps.listSuperadmins();
|
|
65
|
+
// ============ Lockdown ============
|
|
66
|
+
getLockdownStatus = () => this.lockdownOps.getLockdownStatus();
|
|
67
|
+
getLockdownHistory = (limit) => this.lockdownOps.getLockdownHistory(limit);
|
|
68
|
+
getThreats = (options) => this.lockdownOps.getThreats(options);
|
|
69
|
+
// ============ Audit ============
|
|
70
|
+
listAudit = (options) => this.auditOps.listAudit(options);
|
|
71
|
+
verifyAuditChain = () => this.auditOps.verifyAuditChain();
|
|
72
|
+
// ============ Emergency Operations ============
|
|
73
|
+
testConnection = () => this.emergencyOps.testConnection();
|
|
74
|
+
getUserStatus = (username) => this.emergencyOps.getUserStatus(username);
|
|
75
|
+
resetPassword = (username, newPassword) => this.emergencyOps.resetPassword(username, newPassword);
|
|
76
|
+
unlockUser = (username) => this.emergencyOps.unlockUser(username);
|
|
77
|
+
disableTotp = (username) => this.emergencyOps.disableTotp(username);
|
|
78
|
+
}
|
|
79
|
+
// ============ Legacy exports for backward compatibility ============
|
|
80
|
+
/**
|
|
81
|
+
* Legacy EmergencyDBClient class (alias for LocalDBClient)
|
|
82
|
+
* @deprecated Use LocalDBClient instead
|
|
83
|
+
*/
|
|
84
|
+
export class EmergencyDBClient extends LocalDBClient {
|
|
85
|
+
constructor() {
|
|
86
|
+
// For emergency operations, DATABASE_URL must be set
|
|
87
|
+
if (!process.env.DATABASE_URL) {
|
|
88
|
+
throw new Error('DATABASE_URL environment variable is required for emergency operations.\n' +
|
|
89
|
+
'This should only be set when running directly on a vault node.');
|
|
90
|
+
}
|
|
91
|
+
super();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Check if emergency DB access is available
|
|
96
|
+
*/
|
|
97
|
+
export function isEmergencyDbAvailable() {
|
|
98
|
+
return !!process.env.DATABASE_URL;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Check if local mode is available (more comprehensive check)
|
|
102
|
+
*/
|
|
103
|
+
export function isLocalDbAvailable() {
|
|
104
|
+
const config = getLocalConfig();
|
|
105
|
+
return config !== null;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/db/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lockdown and security operations
|
|
3
|
+
*/
|
|
4
|
+
import type { LockdownStatus, ThreatEvent, LockdownHistoryEntry } from '../../types/index.js';
|
|
5
|
+
import { BaseDBClient } from './client.js';
|
|
6
|
+
export declare class LockdownOperations extends BaseDBClient {
|
|
7
|
+
getLockdownStatus(): Promise<LockdownStatus>;
|
|
8
|
+
getLockdownHistory(limit?: number): Promise<LockdownHistoryEntry[]>;
|
|
9
|
+
getThreats(options?: {
|
|
10
|
+
category?: string;
|
|
11
|
+
since?: string;
|
|
12
|
+
limit?: number;
|
|
13
|
+
}): Promise<ThreatEvent[]>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=lockdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockdown.d.ts","sourceRoot":"","sources":["../../../src/lib/db/lockdown.ts"],"names":[],"mappings":"AAEA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE9F,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,qBAAa,kBAAmB,SAAQ,YAAY;IAC5C,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC;IAwB5C,kBAAkB,CAAC,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAiBvE,UAAU,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;CAoC1G"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Path: src/lib/db/lockdown.ts
|
|
2
|
+
import { BaseDBClient } from './client.js';
|
|
3
|
+
export class LockdownOperations extends BaseDBClient {
|
|
4
|
+
async getLockdownStatus() {
|
|
5
|
+
const row = await this.queryOne('SELECT * FROM lockdown_state ORDER BY updated_at DESC LIMIT 1');
|
|
6
|
+
if (!row) {
|
|
7
|
+
return {
|
|
8
|
+
scope: 'SYSTEM',
|
|
9
|
+
status: 'NORMAL',
|
|
10
|
+
escalationCount: 0,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
scope: row.scope,
|
|
15
|
+
tenantId: row.tenant_id ?? undefined,
|
|
16
|
+
status: row.status,
|
|
17
|
+
reason: row.reason ?? undefined,
|
|
18
|
+
triggeredAt: row.triggered_at?.toISOString(),
|
|
19
|
+
triggeredBy: row.triggered_by ?? undefined,
|
|
20
|
+
escalationCount: row.escalation_count,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async getLockdownHistory(limit = 50) {
|
|
24
|
+
const rows = await this.query('SELECT * FROM lockdown_history ORDER BY created_at DESC LIMIT $1', [limit]);
|
|
25
|
+
return rows.map(r => ({
|
|
26
|
+
id: r.id,
|
|
27
|
+
previousStatus: r.previous_status,
|
|
28
|
+
newStatus: r.new_status,
|
|
29
|
+
transitionReason: r.transition_reason,
|
|
30
|
+
changedByUserId: r.changed_by_user_id ?? undefined,
|
|
31
|
+
changedBySystem: r.changed_by_system,
|
|
32
|
+
ts: r.created_at.toISOString(),
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
async getThreats(options) {
|
|
36
|
+
let sql = 'SELECT * FROM threat_events WHERE 1=1';
|
|
37
|
+
const params = [];
|
|
38
|
+
let paramIndex = 1;
|
|
39
|
+
if (options?.category) {
|
|
40
|
+
sql += ` AND category = $${paramIndex++}`;
|
|
41
|
+
params.push(options.category);
|
|
42
|
+
}
|
|
43
|
+
if (options?.since) {
|
|
44
|
+
sql += ` AND created_at >= $${paramIndex++}`;
|
|
45
|
+
params.push(new Date(options.since));
|
|
46
|
+
}
|
|
47
|
+
sql += ` ORDER BY created_at DESC LIMIT $${paramIndex}`;
|
|
48
|
+
params.push(options?.limit ?? 100);
|
|
49
|
+
const rows = await this.query(sql, params);
|
|
50
|
+
return rows.map(r => ({
|
|
51
|
+
id: r.id,
|
|
52
|
+
ts: r.created_at.toISOString(),
|
|
53
|
+
tenantId: r.tenant_id ?? undefined,
|
|
54
|
+
userId: r.user_id ?? undefined,
|
|
55
|
+
ip: r.ip,
|
|
56
|
+
userAgent: r.user_agent ?? undefined,
|
|
57
|
+
category: r.category,
|
|
58
|
+
signal: r.signal,
|
|
59
|
+
suggestedLevel: r.suggested_level,
|
|
60
|
+
endpoint: r.endpoint,
|
|
61
|
+
method: r.method,
|
|
62
|
+
statusCode: r.status_code,
|
|
63
|
+
escalated: r.escalated,
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=lockdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockdown.js","sourceRoot":"","sources":["../../../src/lib/db/lockdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant database operations
|
|
3
|
+
*/
|
|
4
|
+
import type { TenantWithUsage, TenantUsage } from '../../types/index.js';
|
|
5
|
+
import { BaseDBClient } from './client.js';
|
|
6
|
+
export declare class TenantOperations extends BaseDBClient {
|
|
7
|
+
listTenants(options?: {
|
|
8
|
+
status?: string;
|
|
9
|
+
withUsage?: boolean;
|
|
10
|
+
}): Promise<TenantWithUsage[]>;
|
|
11
|
+
getTenant(id: string, withUsage?: boolean): Promise<TenantWithUsage | null>;
|
|
12
|
+
getTenantUsage(id: string): Promise<TenantUsage>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=tenants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenants.d.ts","sourceRoot":"","sources":["../../../src/lib/db/tenants.ts"],"names":[],"mappings":"AAEA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,qBAAa,gBAAiB,SAAQ,YAAY;IAC1C,WAAW,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA2D3F,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAgC3E,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CA0BvD"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Path: src/lib/db/tenants.ts
|
|
2
|
+
import { BaseDBClient } from './client.js';
|
|
3
|
+
export class TenantOperations extends BaseDBClient {
|
|
4
|
+
async listTenants(options) {
|
|
5
|
+
const withUsage = options?.withUsage ?? false;
|
|
6
|
+
let sql;
|
|
7
|
+
if (withUsage) {
|
|
8
|
+
sql = `
|
|
9
|
+
SELECT t.id, t.name, t.status, t.max_secrets, t.max_kms_keys, t.contact_email,
|
|
10
|
+
t.created_at, t.updated_at,
|
|
11
|
+
(SELECT COUNT(*) FROM secrets WHERE tenant = t.id) as secrets_count,
|
|
12
|
+
(SELECT COUNT(*) FROM kms_keys WHERE tenant_id = t.id) as kms_keys_count,
|
|
13
|
+
(SELECT COUNT(*) FROM users WHERE tenant_id = t.id) as users_count,
|
|
14
|
+
(SELECT COUNT(*) FROM api_keys WHERE tenant_id = t.id) as api_keys_count
|
|
15
|
+
FROM tenants t
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
sql = `
|
|
20
|
+
SELECT t.id, t.name, t.status, t.max_secrets, t.max_kms_keys, t.contact_email,
|
|
21
|
+
t.created_at, t.updated_at
|
|
22
|
+
FROM tenants t
|
|
23
|
+
`;
|
|
24
|
+
}
|
|
25
|
+
const params = [];
|
|
26
|
+
if (options?.status) {
|
|
27
|
+
sql += ' WHERE t.status = $1';
|
|
28
|
+
params.push(options.status);
|
|
29
|
+
}
|
|
30
|
+
sql += ' ORDER BY t.name';
|
|
31
|
+
const rows = await this.query(sql, params);
|
|
32
|
+
return rows.map(r => {
|
|
33
|
+
const tenant = {
|
|
34
|
+
id: r.id,
|
|
35
|
+
name: r.name,
|
|
36
|
+
status: r.status,
|
|
37
|
+
maxSecrets: r.max_secrets ?? undefined,
|
|
38
|
+
maxKmsKeys: r.max_kms_keys ?? undefined,
|
|
39
|
+
contactEmail: r.contact_email ?? undefined,
|
|
40
|
+
createdAt: r.created_at.toISOString(),
|
|
41
|
+
updatedAt: r.updated_at.toISOString(),
|
|
42
|
+
};
|
|
43
|
+
if (withUsage) {
|
|
44
|
+
tenant.usage = {
|
|
45
|
+
secretsCount: parseInt(r.secrets_count ?? '0', 10),
|
|
46
|
+
kmsKeysCount: parseInt(r.kms_keys_count ?? '0', 10),
|
|
47
|
+
storageUsedMb: 0,
|
|
48
|
+
usersCount: parseInt(r.users_count ?? '0', 10),
|
|
49
|
+
apiKeysCount: parseInt(r.api_keys_count ?? '0', 10),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return tenant;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async getTenant(id, withUsage) {
|
|
56
|
+
const row = await this.queryOne('SELECT * FROM tenants WHERE id = $1', [id]);
|
|
57
|
+
if (!row)
|
|
58
|
+
return null;
|
|
59
|
+
const tenant = {
|
|
60
|
+
id: row.id,
|
|
61
|
+
name: row.name,
|
|
62
|
+
status: row.status,
|
|
63
|
+
maxSecrets: row.max_secrets ?? undefined,
|
|
64
|
+
maxKmsKeys: row.max_kms_keys ?? undefined,
|
|
65
|
+
contactEmail: row.contact_email ?? undefined,
|
|
66
|
+
createdAt: row.created_at.toISOString(),
|
|
67
|
+
updatedAt: row.updated_at.toISOString(),
|
|
68
|
+
};
|
|
69
|
+
if (withUsage) {
|
|
70
|
+
tenant.usage = await this.getTenantUsage(id);
|
|
71
|
+
}
|
|
72
|
+
return tenant;
|
|
73
|
+
}
|
|
74
|
+
async getTenantUsage(id) {
|
|
75
|
+
const secrets = await this.queryOne('SELECT COUNT(*) as count FROM secrets WHERE tenant = $1', [id]);
|
|
76
|
+
const kmsKeys = await this.queryOne('SELECT COUNT(*) as count FROM kms_keys WHERE tenant_id = $1', [id]);
|
|
77
|
+
const users = await this.queryOne('SELECT COUNT(*) as count FROM users WHERE tenant_id = $1', [id]);
|
|
78
|
+
const apiKeys = await this.queryOne('SELECT COUNT(*) as count FROM api_keys WHERE tenant_id = $1', [id]);
|
|
79
|
+
return {
|
|
80
|
+
secretsCount: parseInt(secrets?.count ?? '0', 10),
|
|
81
|
+
kmsKeysCount: parseInt(kmsKeys?.count ?? '0', 10),
|
|
82
|
+
storageUsedMb: 0,
|
|
83
|
+
usersCount: parseInt(users?.count ?? '0', 10),
|
|
84
|
+
apiKeysCount: parseInt(apiKeys?.count ?? '0', 10),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=tenants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenants.js","sourceRoot":"","sources":["../../../src/lib/db/tenants.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAQ9B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IAChD,KAAK,CAAC,WAAW,CAAC,OAAkD;QAClE,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,KAAK,CAAC;QAE9C,IAAI,GAAW,CAAC;QAChB,IAAI,SAAS,EAAE,CAAC;YACd,GAAG,GAAG;;;;;;;;OAQL,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,GAAG,GAAG;;;;OAIL,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAc,EAAE,CAAC;QAE7B,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;YACpB,GAAG,IAAI,sBAAsB,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;QAED,GAAG,IAAI,kBAAkB,CAAC;QAE1B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAY,GAAG,EAAE,MAAM,CAAC,CAAC;QAEtD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;YAClB,MAAM,MAAM,GAAoB;gBAC9B,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,MAAM,EAAE,CAAC,CAAC,MAA6C;gBACvD,UAAU,EAAE,CAAC,CAAC,WAAW,IAAI,SAAS;gBACtC,UAAU,EAAE,CAAC,CAAC,YAAY,IAAI,SAAS;gBACvC,YAAY,EAAE,CAAC,CAAC,aAAa,IAAI,SAAS;gBAC1C,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,EAAE;gBACrC,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,EAAE;aACtC,CAAC;YAEF,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,CAAC,KAAK,GAAG;oBACb,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,aAAa,IAAI,GAAG,EAAE,EAAE,CAAC;oBAClD,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,cAAc,IAAI,GAAG,EAAE,EAAE,CAAC;oBACnD,aAAa,EAAE,CAAC;oBAChB,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,WAAW,IAAI,GAAG,EAAE,EAAE,CAAC;oBAC9C,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,cAAc,IAAI,GAAG,EAAE,EAAE,CAAC;iBACpD,CAAC;YACJ,CAAC;YAED,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,EAAU,EAAE,SAAmB;QAC7C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAS5B,qCAAqC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAEhD,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QAEtB,MAAM,MAAM,GAAoB;YAC9B,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,MAAM,EAAE,GAAG,CAAC,MAA6C;YACzD,UAAU,EAAE,GAAG,CAAC,WAAW,IAAI,SAAS;YACxC,UAAU,EAAE,GAAG,CAAC,YAAY,IAAI,SAAS;YACzC,YAAY,EAAE,GAAG,CAAC,aAAa,IAAI,SAAS;YAC5C,SAAS,EAAE,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE;YACvC,SAAS,EAAE,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE;SACxC,CAAC;QAEF,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;QAC/C,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,EAAU;QAC7B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CACjC,yDAAyD,EACzD,CAAC,EAAE,CAAC,CACL,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CACjC,6DAA6D,EAC7D,CAAC,EAAE,CAAC,CACL,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAC/B,0DAA0D,EAC1D,CAAC,EAAE,CAAC,CACL,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CACjC,6DAA6D,EAC7D,CAAC,EAAE,CAAC,CACL,CAAC;QAEF,OAAO;YACL,YAAY,EAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,IAAI,GAAG,EAAE,EAAE,CAAC;YACjD,YAAY,EAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,IAAI,GAAG,EAAE,EAAE,CAAC;YACjD,aAAa,EAAE,CAAC;YAChB,UAAU,EAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,IAAI,GAAG,EAAE,EAAE,CAAC;YAC7C,YAAY,EAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,IAAI,GAAG,EAAE,EAAE,CAAC;SAClD,CAAC;IACJ,CAAC;CACF"}
|