@pan-sec/notebooklm-mcp 1.4.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/LICENSE +21 -0
- package/README.md +289 -0
- package/SECURITY.md +539 -0
- package/dist/auth/auth-manager.d.ts +137 -0
- package/dist/auth/auth-manager.d.ts.map +1 -0
- package/dist/auth/auth-manager.js +984 -0
- package/dist/auth/auth-manager.js.map +1 -0
- package/dist/auth/mcp-auth.d.ts +102 -0
- package/dist/auth/mcp-auth.d.ts.map +1 -0
- package/dist/auth/mcp-auth.js +286 -0
- package/dist/auth/mcp-auth.js.map +1 -0
- package/dist/config.d.ts +89 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +216 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +26 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +41 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +371 -0
- package/dist/index.js.map +1 -0
- package/dist/library/notebook-library.d.ts +70 -0
- package/dist/library/notebook-library.d.ts.map +1 -0
- package/dist/library/notebook-library.js +279 -0
- package/dist/library/notebook-library.js.map +1 -0
- package/dist/library/types.d.ts +67 -0
- package/dist/library/types.d.ts.map +1 -0
- package/dist/library/types.js +8 -0
- package/dist/library/types.js.map +1 -0
- package/dist/resources/resource-handlers.d.ts +22 -0
- package/dist/resources/resource-handlers.d.ts.map +1 -0
- package/dist/resources/resource-handlers.js +216 -0
- package/dist/resources/resource-handlers.js.map +1 -0
- package/dist/session/browser-session.d.ts +108 -0
- package/dist/session/browser-session.d.ts.map +1 -0
- package/dist/session/browser-session.js +621 -0
- package/dist/session/browser-session.js.map +1 -0
- package/dist/session/session-manager.d.ts +77 -0
- package/dist/session/session-manager.d.ts.map +1 -0
- package/dist/session/session-manager.js +314 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/session/session-timeout.d.ts +122 -0
- package/dist/session/session-timeout.d.ts.map +1 -0
- package/dist/session/session-timeout.js +281 -0
- package/dist/session/session-timeout.js.map +1 -0
- package/dist/session/shared-context-manager.d.ts +107 -0
- package/dist/session/shared-context-manager.d.ts.map +1 -0
- package/dist/session/shared-context-manager.js +447 -0
- package/dist/session/shared-context-manager.js.map +1 -0
- package/dist/tools/definitions/ask-question.d.ts +8 -0
- package/dist/tools/definitions/ask-question.d.ts.map +1 -0
- package/dist/tools/definitions/ask-question.js +211 -0
- package/dist/tools/definitions/ask-question.js.map +1 -0
- package/dist/tools/definitions/notebook-management.d.ts +3 -0
- package/dist/tools/definitions/notebook-management.d.ts.map +1 -0
- package/dist/tools/definitions/notebook-management.js +243 -0
- package/dist/tools/definitions/notebook-management.js.map +1 -0
- package/dist/tools/definitions/session-management.d.ts +3 -0
- package/dist/tools/definitions/session-management.d.ts.map +1 -0
- package/dist/tools/definitions/session-management.js +41 -0
- package/dist/tools/definitions/session-management.js.map +1 -0
- package/dist/tools/definitions/system.d.ts +3 -0
- package/dist/tools/definitions/system.d.ts.map +1 -0
- package/dist/tools/definitions/system.js +143 -0
- package/dist/tools/definitions/system.js.map +1 -0
- package/dist/tools/definitions.d.ts +12 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +26 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/handlers.d.ts +213 -0
- package/dist/tools/handlers.d.ts.map +1 -0
- package/dist/tools/handlers.js +813 -0
- package/dist/tools/handlers.js.map +1 -0
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +8 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types.d.ts +82 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/audit-logger.d.ts +140 -0
- package/dist/utils/audit-logger.d.ts.map +1 -0
- package/dist/utils/audit-logger.js +361 -0
- package/dist/utils/audit-logger.js.map +1 -0
- package/dist/utils/cert-pinning.d.ts +97 -0
- package/dist/utils/cert-pinning.d.ts.map +1 -0
- package/dist/utils/cert-pinning.js +328 -0
- package/dist/utils/cert-pinning.js.map +1 -0
- package/dist/utils/cleanup-manager.d.ts +133 -0
- package/dist/utils/cleanup-manager.d.ts.map +1 -0
- package/dist/utils/cleanup-manager.js +673 -0
- package/dist/utils/cleanup-manager.js.map +1 -0
- package/dist/utils/cli-handler.d.ts +16 -0
- package/dist/utils/cli-handler.d.ts.map +1 -0
- package/dist/utils/cli-handler.js +102 -0
- package/dist/utils/cli-handler.js.map +1 -0
- package/dist/utils/crypto.d.ts +175 -0
- package/dist/utils/crypto.d.ts.map +1 -0
- package/dist/utils/crypto.js +612 -0
- package/dist/utils/crypto.js.map +1 -0
- package/dist/utils/logger.d.ts +61 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +92 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/page-utils.d.ts +54 -0
- package/dist/utils/page-utils.d.ts.map +1 -0
- package/dist/utils/page-utils.js +405 -0
- package/dist/utils/page-utils.js.map +1 -0
- package/dist/utils/response-validator.d.ts +98 -0
- package/dist/utils/response-validator.d.ts.map +1 -0
- package/dist/utils/response-validator.js +352 -0
- package/dist/utils/response-validator.js.map +1 -0
- package/dist/utils/secrets-scanner.d.ts +126 -0
- package/dist/utils/secrets-scanner.d.ts.map +1 -0
- package/dist/utils/secrets-scanner.js +443 -0
- package/dist/utils/secrets-scanner.js.map +1 -0
- package/dist/utils/secure-memory.d.ts +130 -0
- package/dist/utils/secure-memory.d.ts.map +1 -0
- package/dist/utils/secure-memory.js +279 -0
- package/dist/utils/secure-memory.js.map +1 -0
- package/dist/utils/security.d.ts +83 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +272 -0
- package/dist/utils/security.js.map +1 -0
- package/dist/utils/settings-manager.d.ts +37 -0
- package/dist/utils/settings-manager.d.ts.map +1 -0
- package/dist/utils/settings-manager.js +125 -0
- package/dist/utils/settings-manager.js.map +1 -0
- package/dist/utils/stealth-utils.d.ts +135 -0
- package/dist/utils/stealth-utils.d.ts.map +1 -0
- package/dist/utils/stealth-utils.js +398 -0
- package/dist/utils/stealth-utils.js.map +1 -0
- package/dist/utils/tool-validation.d.ts +93 -0
- package/dist/utils/tool-validation.d.ts.map +1 -0
- package/dist/utils/tool-validation.js +277 -0
- package/dist/utils/tool-validation.js.map +1 -0
- package/docs/SECURITY_IMPLEMENTATION_PLAN.md +437 -0
- package/docs/configuration.md +94 -0
- package/docs/tools.md +34 -0
- package/docs/troubleshooting.md +59 -0
- package/docs/usage-guide.md +245 -0
- package/package.json +82 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure Memory Utilities for NotebookLM MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Provides secure handling of sensitive data in memory:
|
|
5
|
+
* - Zero-fill buffers and strings after use
|
|
6
|
+
* - Secure string class that auto-wipes
|
|
7
|
+
* - Memory-safe credential handling
|
|
8
|
+
*
|
|
9
|
+
* Why this matters:
|
|
10
|
+
* - Prevents memory dump attacks
|
|
11
|
+
* - Reduces credential exposure window
|
|
12
|
+
* - Mitigates cold boot attacks
|
|
13
|
+
*
|
|
14
|
+
* Added by Pantheon Security for hardened fork.
|
|
15
|
+
*/
|
|
16
|
+
import crypto from "crypto";
|
|
17
|
+
/**
|
|
18
|
+
* Securely zero-fill a Buffer
|
|
19
|
+
* Uses crypto.randomFill first to prevent compiler optimization removal
|
|
20
|
+
*/
|
|
21
|
+
export function zeroBuffer(buffer) {
|
|
22
|
+
if (!buffer || buffer.length === 0)
|
|
23
|
+
return;
|
|
24
|
+
// First overwrite with random data (prevents optimization removal)
|
|
25
|
+
crypto.randomFillSync(buffer);
|
|
26
|
+
// Then zero fill
|
|
27
|
+
buffer.fill(0);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Securely zero-fill a Uint8Array
|
|
31
|
+
*/
|
|
32
|
+
export function zeroUint8Array(arr) {
|
|
33
|
+
if (!arr || arr.length === 0)
|
|
34
|
+
return;
|
|
35
|
+
// Overwrite with random then zero
|
|
36
|
+
crypto.randomFillSync(arr);
|
|
37
|
+
arr.fill(0);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create a secure string that can be wiped
|
|
41
|
+
* Note: JavaScript strings are immutable, so we use a Buffer internally
|
|
42
|
+
*/
|
|
43
|
+
export class SecureString {
|
|
44
|
+
buffer;
|
|
45
|
+
wiped = false;
|
|
46
|
+
constructor(value) {
|
|
47
|
+
this.buffer = Buffer.from(value, "utf-8");
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get the string value (creates new string each time)
|
|
51
|
+
*/
|
|
52
|
+
toString() {
|
|
53
|
+
if (this.wiped) {
|
|
54
|
+
throw new Error("SecureString has been wiped");
|
|
55
|
+
}
|
|
56
|
+
return this.buffer.toString("utf-8");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get the underlying buffer (for crypto operations)
|
|
60
|
+
*/
|
|
61
|
+
toBuffer() {
|
|
62
|
+
if (this.wiped) {
|
|
63
|
+
throw new Error("SecureString has been wiped");
|
|
64
|
+
}
|
|
65
|
+
return this.buffer;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get length without exposing content
|
|
69
|
+
*/
|
|
70
|
+
get length() {
|
|
71
|
+
return this.wiped ? 0 : this.buffer.length;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Securely wipe the string from memory
|
|
75
|
+
*/
|
|
76
|
+
wipe() {
|
|
77
|
+
if (!this.wiped) {
|
|
78
|
+
zeroBuffer(this.buffer);
|
|
79
|
+
this.wiped = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if already wiped
|
|
84
|
+
*/
|
|
85
|
+
isWiped() {
|
|
86
|
+
return this.wiped;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Secure credential holder with automatic wiping
|
|
91
|
+
*/
|
|
92
|
+
export class SecureCredential {
|
|
93
|
+
value;
|
|
94
|
+
createdAt;
|
|
95
|
+
maxAgeMs;
|
|
96
|
+
autoWipeTimer;
|
|
97
|
+
constructor(credential, maxAgeMs = 300000) {
|
|
98
|
+
this.value = new SecureString(credential);
|
|
99
|
+
this.createdAt = Date.now();
|
|
100
|
+
this.maxAgeMs = maxAgeMs;
|
|
101
|
+
// Auto-wipe after max age
|
|
102
|
+
this.autoWipeTimer = setTimeout(() => {
|
|
103
|
+
this.wipe();
|
|
104
|
+
}, maxAgeMs);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get the credential value
|
|
108
|
+
*/
|
|
109
|
+
getValue() {
|
|
110
|
+
if (this.isExpired()) {
|
|
111
|
+
this.wipe();
|
|
112
|
+
throw new Error("Credential has expired");
|
|
113
|
+
}
|
|
114
|
+
return this.value.toString();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Check if credential has expired
|
|
118
|
+
*/
|
|
119
|
+
isExpired() {
|
|
120
|
+
return Date.now() - this.createdAt > this.maxAgeMs;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get time remaining before auto-wipe (ms)
|
|
124
|
+
*/
|
|
125
|
+
getTimeRemaining() {
|
|
126
|
+
const remaining = this.maxAgeMs - (Date.now() - this.createdAt);
|
|
127
|
+
return Math.max(0, remaining);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Securely wipe the credential
|
|
131
|
+
*/
|
|
132
|
+
wipe() {
|
|
133
|
+
if (this.autoWipeTimer) {
|
|
134
|
+
clearTimeout(this.autoWipeTimer);
|
|
135
|
+
this.autoWipeTimer = undefined;
|
|
136
|
+
}
|
|
137
|
+
this.value.wipe();
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Check if already wiped
|
|
141
|
+
*/
|
|
142
|
+
isWiped() {
|
|
143
|
+
return this.value.isWiped();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Secure object that wipes all string/buffer properties on dispose
|
|
148
|
+
*/
|
|
149
|
+
export class SecureObject {
|
|
150
|
+
data;
|
|
151
|
+
disposed = false;
|
|
152
|
+
constructor(data) {
|
|
153
|
+
this.data = data;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get a property value
|
|
157
|
+
*/
|
|
158
|
+
get(key) {
|
|
159
|
+
if (this.disposed) {
|
|
160
|
+
throw new Error("SecureObject has been disposed");
|
|
161
|
+
}
|
|
162
|
+
return this.data[key];
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get all data (use carefully)
|
|
166
|
+
*/
|
|
167
|
+
getData() {
|
|
168
|
+
if (this.disposed) {
|
|
169
|
+
throw new Error("SecureObject has been disposed");
|
|
170
|
+
}
|
|
171
|
+
return this.data;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Dispose and wipe all sensitive data
|
|
175
|
+
*/
|
|
176
|
+
dispose() {
|
|
177
|
+
if (this.disposed)
|
|
178
|
+
return;
|
|
179
|
+
for (const key of Object.keys(this.data)) {
|
|
180
|
+
const value = this.data[key];
|
|
181
|
+
if (Buffer.isBuffer(value)) {
|
|
182
|
+
zeroBuffer(value);
|
|
183
|
+
}
|
|
184
|
+
else if (value instanceof Uint8Array) {
|
|
185
|
+
zeroUint8Array(value);
|
|
186
|
+
}
|
|
187
|
+
else if (value instanceof SecureString) {
|
|
188
|
+
value.wipe();
|
|
189
|
+
}
|
|
190
|
+
else if (value instanceof SecureCredential) {
|
|
191
|
+
value.wipe();
|
|
192
|
+
}
|
|
193
|
+
else if (typeof value === "string") {
|
|
194
|
+
// Can't truly wipe JS strings, but we can dereference
|
|
195
|
+
this.data[key] = "";
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
this.disposed = true;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Check if disposed
|
|
202
|
+
*/
|
|
203
|
+
isDisposed() {
|
|
204
|
+
return this.disposed;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Execute a function with a secure credential, auto-wiping after use
|
|
209
|
+
*/
|
|
210
|
+
export async function withSecureCredential(credential, fn) {
|
|
211
|
+
const secureCred = new SecureCredential(credential);
|
|
212
|
+
try {
|
|
213
|
+
return await fn(secureCred);
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
secureCred.wipe();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Execute a function with a secure buffer, auto-wiping after use
|
|
221
|
+
*/
|
|
222
|
+
export async function withSecureBuffer(data, fn) {
|
|
223
|
+
try {
|
|
224
|
+
return await fn(data);
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
zeroBuffer(data);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Create a secure copy of a buffer that will be wiped on GC
|
|
232
|
+
* Uses FinalizationRegistry for automatic cleanup
|
|
233
|
+
*/
|
|
234
|
+
const bufferRegistry = new FinalizationRegistry((held) => {
|
|
235
|
+
zeroBuffer(held.buffer);
|
|
236
|
+
});
|
|
237
|
+
export function createSecureBuffer(arg, encoding) {
|
|
238
|
+
let buffer;
|
|
239
|
+
if (typeof arg === "number") {
|
|
240
|
+
buffer = Buffer.alloc(arg);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
buffer = Buffer.from(arg, encoding);
|
|
244
|
+
}
|
|
245
|
+
// Register for auto-cleanup on GC
|
|
246
|
+
// Note: holdings must be different from target
|
|
247
|
+
bufferRegistry.register(buffer, { buffer });
|
|
248
|
+
return buffer;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Secure comparison to prevent timing attacks
|
|
252
|
+
*/
|
|
253
|
+
export function secureCompare(a, b) {
|
|
254
|
+
const bufA = typeof a === "string" ? Buffer.from(a) : a;
|
|
255
|
+
const bufB = typeof b === "string" ? Buffer.from(b) : b;
|
|
256
|
+
if (bufA.length !== bufB.length) {
|
|
257
|
+
// Still do the comparison to maintain constant time
|
|
258
|
+
crypto.timingSafeEqual(bufA, Buffer.alloc(bufA.length));
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
return crypto.timingSafeEqual(bufA, bufB);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Generate a secure random string
|
|
265
|
+
*/
|
|
266
|
+
export function secureRandomString(length, encoding = "base64url") {
|
|
267
|
+
const bytes = Math.ceil(length * 0.75); // base64 expands ~33%
|
|
268
|
+
return crypto.randomBytes(bytes).toString(encoding).slice(0, length);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Mask sensitive data for logging (doesn't expose real length)
|
|
272
|
+
*/
|
|
273
|
+
export function maskSensitive(value, showChars = 4) {
|
|
274
|
+
if (!value || value.length <= showChars) {
|
|
275
|
+
return "****";
|
|
276
|
+
}
|
|
277
|
+
return value.slice(0, showChars) + "****";
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=secure-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secure-memory.js","sourceRoot":"","sources":["../../src/utils/secure-memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Utilities for NotebookLM MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Provides input validation, sanitization, and security hardening.
|
|
5
|
+
* Added by Pantheon Security for hardened fork.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Validate and sanitize a NotebookLM URL
|
|
9
|
+
* Prevents URL injection, javascript: URLs, and other attacks
|
|
10
|
+
*
|
|
11
|
+
* @param url - The URL to validate
|
|
12
|
+
* @returns Validated URL or throws error
|
|
13
|
+
*/
|
|
14
|
+
export declare function validateNotebookUrl(url: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Validate notebook ID format
|
|
17
|
+
* NotebookLM IDs are typically alphanumeric with dashes
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateNotebookId(id: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Validate session ID format
|
|
22
|
+
*/
|
|
23
|
+
export declare function validateSessionId(id: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Validate question input
|
|
26
|
+
* Prevents extremely long inputs that could cause DoS
|
|
27
|
+
*/
|
|
28
|
+
export declare function validateQuestion(question: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Sanitize a string for safe logging
|
|
31
|
+
* Masks sensitive information like passwords, tokens, etc.
|
|
32
|
+
*/
|
|
33
|
+
export declare function sanitizeForLogging(value: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Mask an email for logging (more aggressive than general sanitization)
|
|
36
|
+
*/
|
|
37
|
+
export declare function maskEmail(email: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Validate file path to prevent path traversal
|
|
40
|
+
*/
|
|
41
|
+
export declare function validateFilePath(basePath: string, filePath: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* Rate limiter for preventing abuse
|
|
44
|
+
*/
|
|
45
|
+
export declare class RateLimiter {
|
|
46
|
+
private requests;
|
|
47
|
+
private readonly maxRequests;
|
|
48
|
+
private readonly windowMs;
|
|
49
|
+
constructor(maxRequests?: number, windowMs?: number);
|
|
50
|
+
/**
|
|
51
|
+
* Check if a request should be allowed
|
|
52
|
+
* @param key - Identifier for the rate limit (e.g., session ID, IP)
|
|
53
|
+
* @returns true if allowed, false if rate limited
|
|
54
|
+
*/
|
|
55
|
+
isAllowed(key: string): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Get remaining requests for a key
|
|
58
|
+
*/
|
|
59
|
+
getRemaining(key: string): number;
|
|
60
|
+
/**
|
|
61
|
+
* Clear all rate limit data
|
|
62
|
+
*/
|
|
63
|
+
clear(): void;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Custom security error class
|
|
67
|
+
*/
|
|
68
|
+
export declare class SecurityError extends Error {
|
|
69
|
+
constructor(message: string);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Environment variable validator
|
|
73
|
+
* Ensures sensitive env vars are not logged
|
|
74
|
+
*/
|
|
75
|
+
export declare function getSecureEnvVar(name: string, defaultValue?: string): string;
|
|
76
|
+
/**
|
|
77
|
+
* Check if running in a secure context
|
|
78
|
+
*/
|
|
79
|
+
export declare function checkSecurityContext(): {
|
|
80
|
+
secure: boolean;
|
|
81
|
+
warnings: string[];
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/utils/security.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoBH;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkDvD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAmBrD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAkBpD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAkBzD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA6BxD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAU/C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAe3E;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,WAAW,GAAE,MAAY,EAAE,QAAQ,GAAE,MAAc;IAK/D;;;;OAIG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAsB/B;;OAEG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAOjC;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,GAAE,MAAW,GAAG,MAAM,CAG/E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAsB9E"}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Utilities for NotebookLM MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Provides input validation, sanitization, and security hardening.
|
|
5
|
+
* Added by Pantheon Security for hardened fork.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Allowed URL patterns for NotebookLM
|
|
9
|
+
*/
|
|
10
|
+
const ALLOWED_NOTEBOOK_DOMAINS = [
|
|
11
|
+
'notebooklm.google.com',
|
|
12
|
+
'notebooklm.google.co.uk',
|
|
13
|
+
'notebooklm.google.de',
|
|
14
|
+
'notebooklm.google.fr',
|
|
15
|
+
'notebooklm.google.es',
|
|
16
|
+
'notebooklm.google.it',
|
|
17
|
+
'notebooklm.google.nl',
|
|
18
|
+
'notebooklm.google.com.au',
|
|
19
|
+
'notebooklm.google.ca',
|
|
20
|
+
];
|
|
21
|
+
// Auth domains (reserved for future use)
|
|
22
|
+
// const ALLOWED_AUTH_DOMAINS = ['accounts.google.com'];
|
|
23
|
+
/**
|
|
24
|
+
* Validate and sanitize a NotebookLM URL
|
|
25
|
+
* Prevents URL injection, javascript: URLs, and other attacks
|
|
26
|
+
*
|
|
27
|
+
* @param url - The URL to validate
|
|
28
|
+
* @returns Validated URL or throws error
|
|
29
|
+
*/
|
|
30
|
+
export function validateNotebookUrl(url) {
|
|
31
|
+
if (!url || typeof url !== 'string') {
|
|
32
|
+
throw new SecurityError('URL is required and must be a string');
|
|
33
|
+
}
|
|
34
|
+
// Trim whitespace
|
|
35
|
+
const trimmed = url.trim();
|
|
36
|
+
// Block empty URLs
|
|
37
|
+
if (trimmed.length === 0) {
|
|
38
|
+
throw new SecurityError('URL cannot be empty');
|
|
39
|
+
}
|
|
40
|
+
// Block dangerous protocols
|
|
41
|
+
const lowerUrl = trimmed.toLowerCase();
|
|
42
|
+
const dangerousProtocols = ['javascript:', 'data:', 'vbscript:', 'file:', 'about:'];
|
|
43
|
+
for (const protocol of dangerousProtocols) {
|
|
44
|
+
if (lowerUrl.startsWith(protocol)) {
|
|
45
|
+
throw new SecurityError(`Dangerous protocol not allowed: ${protocol}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Parse URL
|
|
49
|
+
let parsed;
|
|
50
|
+
try {
|
|
51
|
+
parsed = new URL(trimmed);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
throw new SecurityError('Invalid URL format');
|
|
55
|
+
}
|
|
56
|
+
// Enforce HTTPS
|
|
57
|
+
if (parsed.protocol !== 'https:') {
|
|
58
|
+
throw new SecurityError('Only HTTPS URLs are allowed');
|
|
59
|
+
}
|
|
60
|
+
// Validate domain
|
|
61
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
62
|
+
const isAllowedNotebook = ALLOWED_NOTEBOOK_DOMAINS.some(d => hostname === d || hostname.endsWith('.' + d));
|
|
63
|
+
if (!isAllowedNotebook) {
|
|
64
|
+
throw new SecurityError(`Domain not allowed: ${hostname}. Only NotebookLM domains are permitted.`);
|
|
65
|
+
}
|
|
66
|
+
// Block path traversal attempts
|
|
67
|
+
if (parsed.pathname.includes('..') || parsed.pathname.includes('%2e%2e')) {
|
|
68
|
+
throw new SecurityError('Path traversal not allowed');
|
|
69
|
+
}
|
|
70
|
+
// Return the validated, normalized URL
|
|
71
|
+
return parsed.href;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Validate notebook ID format
|
|
75
|
+
* NotebookLM IDs are typically alphanumeric with dashes
|
|
76
|
+
*/
|
|
77
|
+
export function validateNotebookId(id) {
|
|
78
|
+
if (!id || typeof id !== 'string') {
|
|
79
|
+
throw new SecurityError('Notebook ID is required and must be a string');
|
|
80
|
+
}
|
|
81
|
+
const trimmed = id.trim();
|
|
82
|
+
// Allow alphanumeric, dashes, underscores (typical Google ID format)
|
|
83
|
+
const validPattern = /^[a-zA-Z0-9_-]+$/;
|
|
84
|
+
if (!validPattern.test(trimmed)) {
|
|
85
|
+
throw new SecurityError('Invalid notebook ID format. Only alphanumeric characters, dashes, and underscores allowed.');
|
|
86
|
+
}
|
|
87
|
+
// Reasonable length limit
|
|
88
|
+
if (trimmed.length > 128) {
|
|
89
|
+
throw new SecurityError('Notebook ID too long (max 128 characters)');
|
|
90
|
+
}
|
|
91
|
+
return trimmed;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Validate session ID format
|
|
95
|
+
*/
|
|
96
|
+
export function validateSessionId(id) {
|
|
97
|
+
if (!id || typeof id !== 'string') {
|
|
98
|
+
throw new SecurityError('Session ID is required and must be a string');
|
|
99
|
+
}
|
|
100
|
+
const trimmed = id.trim();
|
|
101
|
+
// UUID-like format or alphanumeric
|
|
102
|
+
const validPattern = /^[a-zA-Z0-9_-]+$/;
|
|
103
|
+
if (!validPattern.test(trimmed)) {
|
|
104
|
+
throw new SecurityError('Invalid session ID format');
|
|
105
|
+
}
|
|
106
|
+
if (trimmed.length > 64) {
|
|
107
|
+
throw new SecurityError('Session ID too long (max 64 characters)');
|
|
108
|
+
}
|
|
109
|
+
return trimmed;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Validate question input
|
|
113
|
+
* Prevents extremely long inputs that could cause DoS
|
|
114
|
+
*/
|
|
115
|
+
export function validateQuestion(question) {
|
|
116
|
+
if (!question || typeof question !== 'string') {
|
|
117
|
+
throw new SecurityError('Question is required and must be a string');
|
|
118
|
+
}
|
|
119
|
+
const trimmed = question.trim();
|
|
120
|
+
if (trimmed.length === 0) {
|
|
121
|
+
throw new SecurityError('Question cannot be empty');
|
|
122
|
+
}
|
|
123
|
+
// Reasonable max length (NotebookLM has its own limits)
|
|
124
|
+
const MAX_QUESTION_LENGTH = 32000;
|
|
125
|
+
if (trimmed.length > MAX_QUESTION_LENGTH) {
|
|
126
|
+
throw new SecurityError(`Question too long (max ${MAX_QUESTION_LENGTH} characters)`);
|
|
127
|
+
}
|
|
128
|
+
return trimmed;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Sanitize a string for safe logging
|
|
132
|
+
* Masks sensitive information like passwords, tokens, etc.
|
|
133
|
+
*/
|
|
134
|
+
export function sanitizeForLogging(value) {
|
|
135
|
+
if (!value || typeof value !== 'string') {
|
|
136
|
+
return '[invalid]';
|
|
137
|
+
}
|
|
138
|
+
// Mask email addresses (show first char and domain)
|
|
139
|
+
const emailMasked = value.replace(/([a-zA-Z0-9._%+-])([a-zA-Z0-9._%+-]*)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g, (_, first, rest, domain) => `${first}${'*'.repeat(Math.min(rest.length, 8))}@${domain}`);
|
|
140
|
+
// Mask anything that looks like a password or secret
|
|
141
|
+
const secretPatterns = [
|
|
142
|
+
/password[=:]\s*["']?([^"'\s]+)/gi,
|
|
143
|
+
/secret[=:]\s*["']?([^"'\s]+)/gi,
|
|
144
|
+
/token[=:]\s*["']?([^"'\s]+)/gi,
|
|
145
|
+
/api[_-]?key[=:]\s*["']?([^"'\s]+)/gi,
|
|
146
|
+
/auth[=:]\s*["']?([^"'\s]+)/gi,
|
|
147
|
+
];
|
|
148
|
+
let result = emailMasked;
|
|
149
|
+
for (const pattern of secretPatterns) {
|
|
150
|
+
result = result.replace(pattern, (match, _secret) => {
|
|
151
|
+
const prefix = match.split(/[=:]/)[0];
|
|
152
|
+
return `${prefix}=[REDACTED]`;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Mask an email for logging (more aggressive than general sanitization)
|
|
159
|
+
*/
|
|
160
|
+
export function maskEmail(email) {
|
|
161
|
+
if (!email || typeof email !== 'string' || !email.includes('@')) {
|
|
162
|
+
return '***@***.***';
|
|
163
|
+
}
|
|
164
|
+
const [name, domain] = email.split('@');
|
|
165
|
+
if (name.length <= 2) {
|
|
166
|
+
return `${'*'.repeat(name.length)}@${domain}`;
|
|
167
|
+
}
|
|
168
|
+
return `${name[0]}${'*'.repeat(name.length - 2)}${name[name.length - 1]}@${domain}`;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Validate file path to prevent path traversal
|
|
172
|
+
*/
|
|
173
|
+
export function validateFilePath(basePath, filePath) {
|
|
174
|
+
const path = require('path');
|
|
175
|
+
// Resolve to absolute path
|
|
176
|
+
const resolved = path.resolve(basePath, filePath);
|
|
177
|
+
// Ensure it's within the base path
|
|
178
|
+
const normalizedBase = path.normalize(basePath);
|
|
179
|
+
const normalizedResolved = path.normalize(resolved);
|
|
180
|
+
if (!normalizedResolved.startsWith(normalizedBase)) {
|
|
181
|
+
throw new SecurityError('Path traversal detected: file must be within allowed directory');
|
|
182
|
+
}
|
|
183
|
+
return normalizedResolved;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Rate limiter for preventing abuse
|
|
187
|
+
*/
|
|
188
|
+
export class RateLimiter {
|
|
189
|
+
requests = new Map();
|
|
190
|
+
maxRequests;
|
|
191
|
+
windowMs;
|
|
192
|
+
constructor(maxRequests = 100, windowMs = 60000) {
|
|
193
|
+
this.maxRequests = maxRequests;
|
|
194
|
+
this.windowMs = windowMs;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Check if a request should be allowed
|
|
198
|
+
* @param key - Identifier for the rate limit (e.g., session ID, IP)
|
|
199
|
+
* @returns true if allowed, false if rate limited
|
|
200
|
+
*/
|
|
201
|
+
isAllowed(key) {
|
|
202
|
+
const now = Date.now();
|
|
203
|
+
const windowStart = now - this.windowMs;
|
|
204
|
+
// Get existing requests for this key
|
|
205
|
+
let requests = this.requests.get(key) || [];
|
|
206
|
+
// Filter to only requests within the window
|
|
207
|
+
requests = requests.filter(timestamp => timestamp > windowStart);
|
|
208
|
+
// Check if under limit
|
|
209
|
+
if (requests.length >= this.maxRequests) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
// Add current request
|
|
213
|
+
requests.push(now);
|
|
214
|
+
this.requests.set(key, requests);
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Get remaining requests for a key
|
|
219
|
+
*/
|
|
220
|
+
getRemaining(key) {
|
|
221
|
+
const now = Date.now();
|
|
222
|
+
const windowStart = now - this.windowMs;
|
|
223
|
+
const requests = (this.requests.get(key) || []).filter(t => t > windowStart);
|
|
224
|
+
return Math.max(0, this.maxRequests - requests.length);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Clear all rate limit data
|
|
228
|
+
*/
|
|
229
|
+
clear() {
|
|
230
|
+
this.requests.clear();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Custom security error class
|
|
235
|
+
*/
|
|
236
|
+
export class SecurityError extends Error {
|
|
237
|
+
constructor(message) {
|
|
238
|
+
super(message);
|
|
239
|
+
this.name = 'SecurityError';
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Environment variable validator
|
|
244
|
+
* Ensures sensitive env vars are not logged
|
|
245
|
+
*/
|
|
246
|
+
export function getSecureEnvVar(name, defaultValue = '') {
|
|
247
|
+
const value = process.env[name];
|
|
248
|
+
return value !== undefined ? value : defaultValue;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Check if running in a secure context
|
|
252
|
+
*/
|
|
253
|
+
export function checkSecurityContext() {
|
|
254
|
+
const warnings = [];
|
|
255
|
+
// Check for plaintext credentials in env
|
|
256
|
+
if (process.env.LOGIN_PASSWORD) {
|
|
257
|
+
warnings.push('LOGIN_PASSWORD is set in environment - consider using a secrets manager');
|
|
258
|
+
}
|
|
259
|
+
// Check for debug mode
|
|
260
|
+
if (process.env.DEBUG === 'true' || process.env.NODE_ENV === 'development') {
|
|
261
|
+
warnings.push('Running in debug/development mode - ensure this is intentional');
|
|
262
|
+
}
|
|
263
|
+
// Check for headless mode (visible browser can leak info)
|
|
264
|
+
if (process.env.HEADLESS === 'false') {
|
|
265
|
+
warnings.push('Browser is running in visible mode - screen may expose sensitive data');
|
|
266
|
+
}
|
|
267
|
+
return {
|
|
268
|
+
secure: warnings.length === 0,
|
|
269
|
+
warnings,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/utils/security.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,wBAAwB,GAAG;IAC/B,uBAAuB;IACvB,yBAAyB;IACzB,sBAAsB;IACtB,sBAAsB;IACtB,sBAAsB;IACtB,sBAAsB;IACtB,sBAAsB;IACtB,0BAA0B;IAC1B,sBAAsB;CACvB,CAAC;AAEF,yCAAyC;AACzC,wDAAwD;AAExD;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACpC,MAAM,IAAI,aAAa,CAAC,sCAAsC,CAAC,CAAC;IAClE,CAAC;IAED,kBAAkB;IAClB,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAE3B,mBAAmB;IACnB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,aAAa,CAAC,qBAAqB,CAAC,CAAC;IACjD,CAAC;IAED,4BAA4B;IAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,kBAAkB,GAAG,CAAC,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACpF,KAAK,MAAM,QAAQ,IAAI,kBAAkB,EAAE,CAAC;QAC1C,IAAI,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,aAAa,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IAED,YAAY;IACZ,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,aAAa,CAAC,oBAAoB,CAAC,CAAC;IAChD,CAAC;IAED,gBAAgB;IAChB,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,aAAa,CAAC,6BAA6B,CAAC,CAAC;IACzD,CAAC;IAED,kBAAkB;IAClB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IAC/C,MAAM,iBAAiB,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,KAAK,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAE3G,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,MAAM,IAAI,aAAa,CAAC,uBAAuB,QAAQ,0CAA0C,CAAC,CAAC;IACrG,CAAC;IAED,gCAAgC;IAChC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzE,MAAM,IAAI,aAAa,CAAC,4BAA4B,CAAC,CAAC;IACxD,CAAC;IAED,uCAAuC;IACvC,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,EAAU;IAC3C,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,IAAI,aAAa,CAAC,8CAA8C,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;IAE1B,qEAAqE;IACrE,MAAM,YAAY,GAAG,kBAAkB,CAAC;IACxC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,aAAa,CAAC,4FAA4F,CAAC,CAAC;IACxH,CAAC;IAED,0BAA0B;IAC1B,IAAI,OAAO,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QACzB,MAAM,IAAI,aAAa,CAAC,2CAA2C,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAU;IAC1C,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,IAAI,aAAa,CAAC,6CAA6C,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;IAE1B,mCAAmC;IACnC,MAAM,YAAY,GAAG,kBAAkB,CAAC;IACxC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,aAAa,CAAC,2BAA2B,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACxB,MAAM,IAAI,aAAa,CAAC,yCAAyC,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9C,MAAM,IAAI,aAAa,CAAC,2CAA2C,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAEhC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,aAAa,CAAC,0BAA0B,CAAC,CAAC;IACtD,CAAC;IAED,wDAAwD;IACxD,MAAM,mBAAmB,GAAG,KAAK,CAAC;IAClC,IAAI,OAAO,CAAC,MAAM,GAAG,mBAAmB,EAAE,CAAC;QACzC,MAAM,IAAI,aAAa,CAAC,0BAA0B,mBAAmB,cAAc,CAAC,CAAC;IACvF,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,oDAAoD;IACpD,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAC/B,uEAAuE,EACvE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CACxF,CAAC;IAEF,qDAAqD;IACrD,MAAM,cAAc,GAAG;QACrB,kCAAkC;QAClC,gCAAgC;QAChC,+BAA+B;QAC/B,qCAAqC;QACrC,8BAA8B;KAC/B,CAAC;IAEF,IAAI,MAAM,GAAG,WAAW,CAAC;IACzB,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;QACrC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAClD,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACtC,OAAO,GAAG,MAAM,aAAa,CAAC;QAChC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAChE,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACrB,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC;AACtF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,QAAgB;IACjE,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7B,2BAA2B;IAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAElD,mCAAmC;IACnC,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,kBAAkB,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAEpD,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,aAAa,CAAC,gEAAgE,CAAC,CAAC;IAC5F,CAAC;IAED,OAAO,kBAAkB,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,OAAO,WAAW;IACd,QAAQ,GAA0B,IAAI,GAAG,EAAE,CAAC;IACnC,WAAW,CAAS;IACpB,QAAQ,CAAS;IAElC,YAAY,cAAsB,GAAG,EAAE,WAAmB,KAAK;QAC7D,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,SAAS,CAAC,GAAW;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,WAAW,GAAG,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC;QAExC,qCAAqC;QACrC,IAAI,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAE5C,4CAA4C;QAC5C,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,GAAG,WAAW,CAAC,CAAC;QAEjE,uBAAuB;QACvB,IAAI,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACxC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,sBAAsB;QACtB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAEjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,GAAW;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,WAAW,GAAG,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC;QACxC,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC;QAC7E,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzD,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,eAAuB,EAAE;IACrE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,yCAAyC;IACzC,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;QAC/B,QAAQ,CAAC,IAAI,CAAC,yEAAyE,CAAC,CAAC;IAC3F,CAAC;IAED,uBAAuB;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;QAC3E,QAAQ,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC;IAClF,CAAC;IAED,0DAA0D;IAC1D,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACrC,QAAQ,CAAC,IAAI,CAAC,uEAAuE,CAAC,CAAC;IACzF,CAAC;IAED,OAAO;QACL,MAAM,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC;QAC7B,QAAQ;KACT,CAAC;AACJ,CAAC"}
|