@plures/pluresdb 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 +72 -0
- package/README.md +450 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/better-sqlite3-shared.d.ts +12 -0
- package/dist/better-sqlite3-shared.d.ts.map +1 -0
- package/dist/better-sqlite3-shared.js +143 -0
- package/dist/better-sqlite3-shared.js.map +1 -0
- package/dist/better-sqlite3.d.ts +4 -0
- package/dist/better-sqlite3.d.ts.map +1 -0
- package/dist/better-sqlite3.js +8 -0
- package/dist/better-sqlite3.js.map +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +258 -0
- package/dist/cli.js.map +1 -0
- package/dist/node-index.d.ts +148 -0
- package/dist/node-index.d.ts.map +1 -0
- package/dist/node-index.js +665 -0
- package/dist/node-index.js.map +1 -0
- package/dist/node-wrapper.d.ts +44 -0
- package/dist/node-wrapper.d.ts.map +1 -0
- package/dist/node-wrapper.js +296 -0
- package/dist/node-wrapper.js.map +1 -0
- package/dist/types/index.d.ts +28 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/node-types.d.ts +71 -0
- package/dist/types/node-types.d.ts.map +1 -0
- package/dist/types/node-types.js +6 -0
- package/dist/types/node-types.js.map +1 -0
- package/dist/vscode/extension.d.ts +81 -0
- package/dist/vscode/extension.d.ts.map +1 -0
- package/dist/vscode/extension.js +309 -0
- package/dist/vscode/extension.js.map +1 -0
- package/examples/basic-usage.d.ts +2 -0
- package/examples/basic-usage.d.ts.map +1 -0
- package/examples/basic-usage.js +26 -0
- package/examples/basic-usage.js.map +1 -0
- package/examples/basic-usage.ts +29 -0
- package/examples/vscode-extension-example/README.md +95 -0
- package/examples/vscode-extension-example/package.json +49 -0
- package/examples/vscode-extension-example/src/extension.ts +172 -0
- package/examples/vscode-extension-example/tsconfig.json +12 -0
- package/examples/vscode-extension-integration.d.ts +31 -0
- package/examples/vscode-extension-integration.d.ts.map +1 -0
- package/examples/vscode-extension-integration.js +319 -0
- package/examples/vscode-extension-integration.js.map +1 -0
- package/examples/vscode-extension-integration.ts +41 -0
- package/legacy/benchmarks/memory-benchmarks.ts +350 -0
- package/legacy/benchmarks/run-benchmarks.ts +315 -0
- package/legacy/better-sqlite3-shared.ts +157 -0
- package/legacy/better-sqlite3.ts +4 -0
- package/legacy/cli.ts +241 -0
- package/legacy/config.ts +50 -0
- package/legacy/core/crdt.ts +107 -0
- package/legacy/core/database.ts +529 -0
- package/legacy/healthcheck.ts +162 -0
- package/legacy/http/api-server.ts +438 -0
- package/legacy/index.ts +28 -0
- package/legacy/logic/rules.ts +46 -0
- package/legacy/main.rs +3 -0
- package/legacy/main.ts +197 -0
- package/legacy/network/websocket-server.ts +115 -0
- package/legacy/node-index.ts +823 -0
- package/legacy/node-wrapper.ts +329 -0
- package/legacy/sqlite-compat.ts +633 -0
- package/legacy/sqlite3-compat.ts +55 -0
- package/legacy/storage/kv-storage.ts +73 -0
- package/legacy/tests/core.test.ts +305 -0
- package/legacy/tests/fixtures/performance-data.json +71 -0
- package/legacy/tests/fixtures/test-data.json +129 -0
- package/legacy/tests/integration/api-server.test.ts +334 -0
- package/legacy/tests/integration/mesh-network.test.ts +303 -0
- package/legacy/tests/logic.test.ts +34 -0
- package/legacy/tests/performance/load.test.ts +290 -0
- package/legacy/tests/security/input-validation.test.ts +286 -0
- package/legacy/tests/unit/core.test.ts +226 -0
- package/legacy/tests/unit/subscriptions.test.ts +135 -0
- package/legacy/tests/unit/vector-search.test.ts +173 -0
- package/legacy/tests/vscode_extension_test.ts +281 -0
- package/legacy/types/index.ts +32 -0
- package/legacy/types/node-types.ts +80 -0
- package/legacy/util/debug.ts +14 -0
- package/legacy/vector/index.ts +59 -0
- package/legacy/vscode/extension.ts +387 -0
- package/package.json +127 -0
- package/scripts/compiled-crud-verify.ts +30 -0
- package/scripts/dogfood.ts +297 -0
- package/scripts/postinstall.js +156 -0
- package/scripts/release-check.js +190 -0
- package/scripts/run-tests.ts +178 -0
- package/scripts/setup-libclang.ps1 +209 -0
- package/scripts/update-changelog.js +214 -0
- package/web/README.md +27 -0
- package/web/svelte/package.json +31 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { assertEquals, assertExists } from "jsr:@std/assert@1.0.14";
|
|
3
|
+
import { GunDB } from "../../core/database.ts";
|
|
4
|
+
|
|
5
|
+
interface PerformanceMetrics {
|
|
6
|
+
operation: string;
|
|
7
|
+
count: number;
|
|
8
|
+
totalTime: number;
|
|
9
|
+
averageTime: number;
|
|
10
|
+
operationsPerSecond: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function measureOperation(
|
|
14
|
+
operation: () => Promise<void>,
|
|
15
|
+
count: number,
|
|
16
|
+
): Promise<PerformanceMetrics> {
|
|
17
|
+
return new Promise(async (resolve) => {
|
|
18
|
+
const startTime = performance.now();
|
|
19
|
+
|
|
20
|
+
for (let i = 0; i < count; i++) {
|
|
21
|
+
await operation();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const endTime = performance.now();
|
|
25
|
+
const totalTime = endTime - startTime;
|
|
26
|
+
const averageTime = totalTime / count;
|
|
27
|
+
const operationsPerSecond = (count / totalTime) * 1000;
|
|
28
|
+
|
|
29
|
+
resolve({
|
|
30
|
+
operation: "unknown",
|
|
31
|
+
count,
|
|
32
|
+
totalTime,
|
|
33
|
+
averageTime,
|
|
34
|
+
operationsPerSecond,
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Deno.test("Performance - Bulk Insert Operations", async () => {
|
|
40
|
+
const db = new GunDB();
|
|
41
|
+
try {
|
|
42
|
+
const kvPath = await Deno.makeTempFile({
|
|
43
|
+
prefix: "kv_",
|
|
44
|
+
suffix: ".sqlite",
|
|
45
|
+
});
|
|
46
|
+
await db.ready(kvPath);
|
|
47
|
+
|
|
48
|
+
const count = 1000;
|
|
49
|
+
let currentCount = 0;
|
|
50
|
+
|
|
51
|
+
const metrics = await measureOperation(async () => {
|
|
52
|
+
await db.put(`perf:${currentCount++}`, {
|
|
53
|
+
id: currentCount,
|
|
54
|
+
data: `Performance test data ${currentCount}`,
|
|
55
|
+
timestamp: Date.now(),
|
|
56
|
+
});
|
|
57
|
+
}, count);
|
|
58
|
+
|
|
59
|
+
console.log(`Bulk Insert Performance:`, metrics);
|
|
60
|
+
|
|
61
|
+
// Verify all data was inserted
|
|
62
|
+
const allNodes = await db.getAll();
|
|
63
|
+
assertEquals(allNodes.length, count);
|
|
64
|
+
|
|
65
|
+
// Performance assertions
|
|
66
|
+
assertEquals(metrics.operationsPerSecond > 100, true); // At least 100 ops/sec
|
|
67
|
+
assertEquals(metrics.averageTime < 10, true); // Less than 10ms per operation
|
|
68
|
+
} finally {
|
|
69
|
+
await db.close();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
Deno.test("Performance - Bulk Read Operations", async () => {
|
|
74
|
+
const db = new GunDB();
|
|
75
|
+
try {
|
|
76
|
+
const kvPath = await Deno.makeTempFile({
|
|
77
|
+
prefix: "kv_",
|
|
78
|
+
suffix: ".sqlite",
|
|
79
|
+
});
|
|
80
|
+
await db.ready(kvPath);
|
|
81
|
+
|
|
82
|
+
// Pre-populate with data
|
|
83
|
+
const count = 1000;
|
|
84
|
+
for (let i = 0; i < count; i++) {
|
|
85
|
+
await db.put(`read:${i}`, {
|
|
86
|
+
id: i,
|
|
87
|
+
data: `Read test data ${i}`,
|
|
88
|
+
timestamp: Date.now(),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let currentCount = 0;
|
|
93
|
+
const metrics = await measureOperation(async () => {
|
|
94
|
+
const data = await db.get(`read:${currentCount++}`);
|
|
95
|
+
assertExists(data);
|
|
96
|
+
}, count);
|
|
97
|
+
|
|
98
|
+
console.log(`Bulk Read Performance:`, metrics);
|
|
99
|
+
|
|
100
|
+
// Performance assertions
|
|
101
|
+
assertEquals(metrics.operationsPerSecond > 500, true); // At least 500 ops/sec
|
|
102
|
+
assertEquals(metrics.averageTime < 2, true); // Less than 2ms per operation
|
|
103
|
+
} finally {
|
|
104
|
+
await db.close();
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
Deno.test("Performance - Vector Search Operations", async () => {
|
|
109
|
+
const db = new GunDB();
|
|
110
|
+
try {
|
|
111
|
+
const kvPath = await Deno.makeTempFile({
|
|
112
|
+
prefix: "kv_",
|
|
113
|
+
suffix: ".sqlite",
|
|
114
|
+
});
|
|
115
|
+
await db.ready(kvPath);
|
|
116
|
+
|
|
117
|
+
// Pre-populate with documents for vector search
|
|
118
|
+
const count = 500;
|
|
119
|
+
for (let i = 0; i < count; i++) {
|
|
120
|
+
await db.put(`doc:${i}`, {
|
|
121
|
+
text:
|
|
122
|
+
`Document ${i} about machine learning and artificial intelligence`,
|
|
123
|
+
content:
|
|
124
|
+
`This is document number ${i} containing information about AI and ML algorithms`,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const searchQueries = [
|
|
129
|
+
"machine learning algorithms",
|
|
130
|
+
"artificial intelligence",
|
|
131
|
+
"neural networks",
|
|
132
|
+
"deep learning",
|
|
133
|
+
"data science",
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
let queryCount = 0;
|
|
137
|
+
const metrics = await measureOperation(async () => {
|
|
138
|
+
const query = searchQueries[queryCount % searchQueries.length];
|
|
139
|
+
const results = await db.vectorSearch(query, 10);
|
|
140
|
+
assertExists(results);
|
|
141
|
+
queryCount++;
|
|
142
|
+
}, 100);
|
|
143
|
+
|
|
144
|
+
console.log(`Vector Search Performance:`, metrics);
|
|
145
|
+
|
|
146
|
+
// Performance assertions
|
|
147
|
+
assertEquals(metrics.operationsPerSecond > 50, true); // At least 50 ops/sec
|
|
148
|
+
assertEquals(metrics.averageTime < 20, true); // Less than 20ms per operation
|
|
149
|
+
} finally {
|
|
150
|
+
await db.close();
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
Deno.test("Performance - Concurrent Operations", async () => {
|
|
155
|
+
const db = new GunDB();
|
|
156
|
+
try {
|
|
157
|
+
const kvPath = await Deno.makeTempFile({
|
|
158
|
+
prefix: "kv_",
|
|
159
|
+
suffix: ".sqlite",
|
|
160
|
+
});
|
|
161
|
+
await db.ready(kvPath);
|
|
162
|
+
|
|
163
|
+
const concurrentCount = 100;
|
|
164
|
+
const operationsPerWorker = 10;
|
|
165
|
+
|
|
166
|
+
const startTime = performance.now();
|
|
167
|
+
|
|
168
|
+
// Run concurrent operations
|
|
169
|
+
const promises = Array.from({ length: concurrentCount }, async (_, i) => {
|
|
170
|
+
for (let j = 0; j < operationsPerWorker; j++) {
|
|
171
|
+
await db.put(`concurrent:${i}:${j}`, {
|
|
172
|
+
worker: i,
|
|
173
|
+
operation: j,
|
|
174
|
+
timestamp: Date.now(),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
await Promise.all(promises);
|
|
180
|
+
|
|
181
|
+
const endTime = performance.now();
|
|
182
|
+
const totalTime = endTime - startTime;
|
|
183
|
+
const totalOperations = concurrentCount * operationsPerWorker;
|
|
184
|
+
const operationsPerSecond = (totalOperations / totalTime) * 1000;
|
|
185
|
+
|
|
186
|
+
console.log(`Concurrent Operations Performance:`, {
|
|
187
|
+
totalOperations,
|
|
188
|
+
totalTime,
|
|
189
|
+
operationsPerSecond,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Verify all operations completed
|
|
193
|
+
const allNodes = await db.getAll();
|
|
194
|
+
assertEquals(allNodes.length, totalOperations);
|
|
195
|
+
|
|
196
|
+
// Performance assertions
|
|
197
|
+
assertEquals(operationsPerSecond > 200, true); // At least 200 ops/sec
|
|
198
|
+
} finally {
|
|
199
|
+
await db.close();
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
Deno.test("Performance - Memory Usage", async () => {
|
|
204
|
+
const db = new GunDB();
|
|
205
|
+
try {
|
|
206
|
+
const kvPath = await Deno.makeTempFile({
|
|
207
|
+
prefix: "kv_",
|
|
208
|
+
suffix: ".sqlite",
|
|
209
|
+
});
|
|
210
|
+
await db.ready(kvPath);
|
|
211
|
+
|
|
212
|
+
const initialMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
213
|
+
|
|
214
|
+
// Insert large amount of data
|
|
215
|
+
const count = 10000;
|
|
216
|
+
for (let i = 0; i < count; i++) {
|
|
217
|
+
await db.put(`memory:${i}`, {
|
|
218
|
+
id: i,
|
|
219
|
+
largeData: "x".repeat(1000), // 1KB per record
|
|
220
|
+
timestamp: Date.now(),
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const afterInsertMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
225
|
+
const memoryIncrease = afterInsertMemory - initialMemory;
|
|
226
|
+
|
|
227
|
+
console.log(`Memory Usage:`, {
|
|
228
|
+
initialMemory,
|
|
229
|
+
afterInsertMemory,
|
|
230
|
+
memoryIncrease,
|
|
231
|
+
memoryPerRecord: memoryIncrease / count,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Memory efficiency assertions
|
|
235
|
+
assertEquals(memoryIncrease < 50 * 1024 * 1024, true); // Less than 50MB increase
|
|
236
|
+
assertEquals(memoryIncrease / count < 5000, true); // Less than 5KB per record
|
|
237
|
+
} finally {
|
|
238
|
+
await db.close();
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
Deno.test("Performance - Subscription Performance", async () => {
|
|
243
|
+
const db = new GunDB();
|
|
244
|
+
try {
|
|
245
|
+
const kvPath = await Deno.makeTempFile({
|
|
246
|
+
prefix: "kv_",
|
|
247
|
+
suffix: ".sqlite",
|
|
248
|
+
});
|
|
249
|
+
await db.ready(kvPath);
|
|
250
|
+
|
|
251
|
+
const subscriptionCount = 1000;
|
|
252
|
+
const updateCount = 100;
|
|
253
|
+
|
|
254
|
+
// Set up many subscriptions
|
|
255
|
+
const subscriptions: Array<() => void> = [];
|
|
256
|
+
for (let i = 0; i < subscriptionCount; i++) {
|
|
257
|
+
const unsubscribe = db.on(`sub:${i}`, () => {});
|
|
258
|
+
subscriptions.push(unsubscribe);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const startTime = performance.now();
|
|
262
|
+
|
|
263
|
+
// Trigger updates
|
|
264
|
+
for (let i = 0; i < updateCount; i++) {
|
|
265
|
+
await db.put(`sub:${i % subscriptionCount}`, {
|
|
266
|
+
update: i,
|
|
267
|
+
timestamp: Date.now(),
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const endTime = performance.now();
|
|
272
|
+
const totalTime = endTime - startTime;
|
|
273
|
+
const updatesPerSecond = (updateCount / totalTime) * 1000;
|
|
274
|
+
|
|
275
|
+
console.log(`Subscription Performance:`, {
|
|
276
|
+
subscriptionCount,
|
|
277
|
+
updateCount,
|
|
278
|
+
totalTime,
|
|
279
|
+
updatesPerSecond,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// Clean up subscriptions
|
|
283
|
+
subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
284
|
+
|
|
285
|
+
// Performance assertions
|
|
286
|
+
assertEquals(updatesPerSecond > 50, true); // At least 50 updates/sec
|
|
287
|
+
} finally {
|
|
288
|
+
await db.close();
|
|
289
|
+
}
|
|
290
|
+
});
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import {
|
|
3
|
+
assertEquals,
|
|
4
|
+
assertExists,
|
|
5
|
+
assertRejects,
|
|
6
|
+
} from "jsr:@std/assert@1.0.14";
|
|
7
|
+
import { GunDB } from "../../core/database.ts";
|
|
8
|
+
|
|
9
|
+
Deno.test("Security - SQL Injection Prevention", async () => {
|
|
10
|
+
const db = new GunDB();
|
|
11
|
+
try {
|
|
12
|
+
const kvPath = await Deno.makeTempFile({
|
|
13
|
+
prefix: "kv_",
|
|
14
|
+
suffix: ".sqlite",
|
|
15
|
+
});
|
|
16
|
+
await db.ready(kvPath);
|
|
17
|
+
|
|
18
|
+
// Test malicious SQL injection attempts
|
|
19
|
+
const maliciousInputs = [
|
|
20
|
+
"'; DROP TABLE users; --",
|
|
21
|
+
"' OR '1'='1",
|
|
22
|
+
"'; INSERT INTO users VALUES ('hacker', 'password'); --",
|
|
23
|
+
"'; UPDATE users SET password='hacked'; --",
|
|
24
|
+
"'; DELETE FROM users; --",
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
for (const maliciousInput of maliciousInputs) {
|
|
28
|
+
// These should be treated as regular string data, not executed as SQL
|
|
29
|
+
await db.put("test:sql", {
|
|
30
|
+
malicious: maliciousInput,
|
|
31
|
+
safe: "normal data",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const result = await db.get("test:sql");
|
|
35
|
+
assertExists(result);
|
|
36
|
+
assertEquals((result as any).malicious, maliciousInput);
|
|
37
|
+
assertEquals((result as any).safe, "normal data");
|
|
38
|
+
}
|
|
39
|
+
} finally {
|
|
40
|
+
await db.close();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
Deno.test("Security - XSS Prevention", async () => {
|
|
45
|
+
const db = new GunDB();
|
|
46
|
+
try {
|
|
47
|
+
const kvPath = await Deno.makeTempFile({
|
|
48
|
+
prefix: "kv_",
|
|
49
|
+
suffix: ".sqlite",
|
|
50
|
+
});
|
|
51
|
+
await db.ready(kvPath);
|
|
52
|
+
|
|
53
|
+
// Test XSS payloads
|
|
54
|
+
const xssPayloads = [
|
|
55
|
+
"<script>alert('xss')</script>",
|
|
56
|
+
"javascript:alert('xss')",
|
|
57
|
+
"<img src=x onerror=alert('xss')>",
|
|
58
|
+
"<svg onload=alert('xss')>",
|
|
59
|
+
"';alert('xss');//",
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
for (const payload of xssPayloads) {
|
|
63
|
+
await db.put("test:xss", {
|
|
64
|
+
payload: payload,
|
|
65
|
+
content: "Safe content",
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const result = await db.get("test:xss");
|
|
69
|
+
assertExists(result);
|
|
70
|
+
// Data should be stored as-is without interpretation
|
|
71
|
+
assertEquals((result as any).payload, payload);
|
|
72
|
+
}
|
|
73
|
+
} finally {
|
|
74
|
+
await db.close();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
Deno.test("Security - Path Traversal Prevention", async () => {
|
|
79
|
+
const db = new GunDB();
|
|
80
|
+
try {
|
|
81
|
+
const kvPath = await Deno.makeTempFile({
|
|
82
|
+
prefix: "kv_",
|
|
83
|
+
suffix: ".sqlite",
|
|
84
|
+
});
|
|
85
|
+
await db.ready(kvPath);
|
|
86
|
+
|
|
87
|
+
// Test path traversal attempts
|
|
88
|
+
const pathTraversalAttempts = [
|
|
89
|
+
"../../../etc/passwd",
|
|
90
|
+
"..\\..\\..\\windows\\system32\\drivers\\etc\\hosts",
|
|
91
|
+
"/etc/passwd",
|
|
92
|
+
"C:\\Windows\\System32\\config\\SAM",
|
|
93
|
+
"....//....//....//etc//passwd",
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
for (const path of pathTraversalAttempts) {
|
|
97
|
+
// These should be treated as regular key names, not file paths
|
|
98
|
+
await db.put(path, {
|
|
99
|
+
content: "This should not access filesystem",
|
|
100
|
+
path: path,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const result = await db.get(path);
|
|
104
|
+
assertExists(result);
|
|
105
|
+
assertEquals((result as any).path, path);
|
|
106
|
+
}
|
|
107
|
+
} finally {
|
|
108
|
+
await db.close();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
Deno.test("Security - Large Payload Prevention", async () => {
|
|
113
|
+
const db = new GunDB();
|
|
114
|
+
try {
|
|
115
|
+
const kvPath = await Deno.makeTempFile({
|
|
116
|
+
prefix: "kv_",
|
|
117
|
+
suffix: ".sqlite",
|
|
118
|
+
});
|
|
119
|
+
await db.ready(kvPath);
|
|
120
|
+
|
|
121
|
+
// Test very large payloads
|
|
122
|
+
const largePayload = "x".repeat(10 * 1024 * 1024); // 10MB
|
|
123
|
+
|
|
124
|
+
await assertRejects(
|
|
125
|
+
async () => {
|
|
126
|
+
await db.put("test:large", {
|
|
127
|
+
data: largePayload,
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
Error,
|
|
131
|
+
"Value too large",
|
|
132
|
+
);
|
|
133
|
+
} finally {
|
|
134
|
+
await db.close();
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
Deno.test("Security - Malformed JSON Handling", async () => {
|
|
139
|
+
const db = new GunDB();
|
|
140
|
+
try {
|
|
141
|
+
const kvPath = await Deno.makeTempFile({
|
|
142
|
+
prefix: "kv_",
|
|
143
|
+
suffix: ".sqlite",
|
|
144
|
+
});
|
|
145
|
+
await db.ready(kvPath);
|
|
146
|
+
|
|
147
|
+
// Test malformed JSON inputs
|
|
148
|
+
const malformedInputs = [
|
|
149
|
+
"{ invalid json }",
|
|
150
|
+
'{ "incomplete": ',
|
|
151
|
+
'{ "nested": { "broken": } }',
|
|
152
|
+
'{ "array": [1, 2, } }',
|
|
153
|
+
'{ "string": "unclosed }',
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
for (const malformed of malformedInputs) {
|
|
157
|
+
await db.put("test:malformed", {
|
|
158
|
+
json: malformed,
|
|
159
|
+
});
|
|
160
|
+
const stored = await db.get("test:malformed");
|
|
161
|
+
assertExists(stored);
|
|
162
|
+
assertEquals((stored as any).json, malformed);
|
|
163
|
+
}
|
|
164
|
+
} finally {
|
|
165
|
+
await db.close();
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
Deno.test("Security - Type Confusion Prevention", async () => {
|
|
170
|
+
const db = new GunDB();
|
|
171
|
+
try {
|
|
172
|
+
const kvPath = await Deno.makeTempFile({
|
|
173
|
+
prefix: "kv_",
|
|
174
|
+
suffix: ".sqlite",
|
|
175
|
+
});
|
|
176
|
+
await db.ready(kvPath);
|
|
177
|
+
|
|
178
|
+
// Test type confusion attempts
|
|
179
|
+
const typeConfusionAttempts = [
|
|
180
|
+
{ __proto__: { isAdmin: true } },
|
|
181
|
+
{ constructor: { prototype: { isAdmin: true } } },
|
|
182
|
+
{ toString: () => "hacked" },
|
|
183
|
+
{ valueOf: () => 999999 },
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
for (const attempt of typeConfusionAttempts) {
|
|
187
|
+
await db.put("test:type", attempt);
|
|
188
|
+
|
|
189
|
+
const result = await db.get("test:type");
|
|
190
|
+
assertExists(result);
|
|
191
|
+
|
|
192
|
+
// Should not have inherited properties
|
|
193
|
+
assertEquals((result as any).isAdmin, undefined);
|
|
194
|
+
assertEquals(typeof (result as any).toString, "string");
|
|
195
|
+
}
|
|
196
|
+
} finally {
|
|
197
|
+
await db.close();
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
Deno.test("Security - Vector Search Injection", async () => {
|
|
202
|
+
const db = new GunDB();
|
|
203
|
+
try {
|
|
204
|
+
const kvPath = await Deno.makeTempFile({
|
|
205
|
+
prefix: "kv_",
|
|
206
|
+
suffix: ".sqlite",
|
|
207
|
+
});
|
|
208
|
+
await db.ready(kvPath);
|
|
209
|
+
|
|
210
|
+
// Test vector search with malicious inputs
|
|
211
|
+
const maliciousQueries = [
|
|
212
|
+
"'; DROP TABLE nodes; --",
|
|
213
|
+
"<script>alert('xss')</script>",
|
|
214
|
+
"../../../etc/passwd",
|
|
215
|
+
"'; INSERT INTO nodes VALUES ('hacked', 'data'); --",
|
|
216
|
+
];
|
|
217
|
+
|
|
218
|
+
for (const query of maliciousQueries) {
|
|
219
|
+
// Vector search should handle these safely
|
|
220
|
+
const results = await db.vectorSearch(query, 5);
|
|
221
|
+
assertEquals(Array.isArray(results), true);
|
|
222
|
+
// Should not throw errors or execute malicious code
|
|
223
|
+
}
|
|
224
|
+
} finally {
|
|
225
|
+
await db.close();
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
Deno.test("Security - Subscription Injection", async () => {
|
|
230
|
+
const db = new GunDB();
|
|
231
|
+
try {
|
|
232
|
+
const kvPath = await Deno.makeTempFile({
|
|
233
|
+
prefix: "kv_",
|
|
234
|
+
suffix: ".sqlite",
|
|
235
|
+
});
|
|
236
|
+
await db.ready(kvPath);
|
|
237
|
+
|
|
238
|
+
// Test subscription with malicious IDs
|
|
239
|
+
const maliciousIds = [
|
|
240
|
+
"'; DROP TABLE nodes; --",
|
|
241
|
+
"<script>alert('xss')</script>",
|
|
242
|
+
"../../../etc/passwd",
|
|
243
|
+
"'; INSERT INTO nodes VALUES ('hacked', 'data'); --",
|
|
244
|
+
];
|
|
245
|
+
|
|
246
|
+
for (const id of maliciousIds) {
|
|
247
|
+
// Subscriptions should handle these safely
|
|
248
|
+
const unsubscribe = db.on(id, () => {});
|
|
249
|
+
assertExists(unsubscribe);
|
|
250
|
+
|
|
251
|
+
// Should be able to unsubscribe safely
|
|
252
|
+
unsubscribe();
|
|
253
|
+
}
|
|
254
|
+
} finally {
|
|
255
|
+
await db.close();
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
Deno.test("Security - Memory Exhaustion Prevention", async () => {
|
|
260
|
+
const db = new GunDB();
|
|
261
|
+
try {
|
|
262
|
+
const kvPath = await Deno.makeTempFile({
|
|
263
|
+
prefix: "kv_",
|
|
264
|
+
suffix: ".sqlite",
|
|
265
|
+
});
|
|
266
|
+
await db.ready(kvPath);
|
|
267
|
+
|
|
268
|
+
// Test creating many subscriptions to exhaust memory
|
|
269
|
+
const subscriptions: Array<() => void> = [];
|
|
270
|
+
|
|
271
|
+
try {
|
|
272
|
+
for (let i = 0; i < 100000; i++) {
|
|
273
|
+
const unsubscribe = db.on(`memory:${i}`, () => {});
|
|
274
|
+
subscriptions.push(unsubscribe);
|
|
275
|
+
}
|
|
276
|
+
} catch (error) {
|
|
277
|
+
// Should fail gracefully with memory limit
|
|
278
|
+
assertEquals(error.message.includes("Memory limit"), true);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Clean up any created subscriptions
|
|
282
|
+
subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
283
|
+
} finally {
|
|
284
|
+
await db.close();
|
|
285
|
+
}
|
|
286
|
+
});
|