@pcircle/evidencemcp-server 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -297
- package/dist/index.d.ts +1 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -123
- package/dist/index.js.map +1 -1
- package/dist/lib/crypto/decrypt.d.ts +11 -0
- package/dist/lib/crypto/decrypt.d.ts.map +1 -0
- package/dist/lib/crypto/decrypt.js +30 -0
- package/dist/lib/crypto/decrypt.js.map +1 -0
- package/dist/lib/crypto/encrypt.d.ts +13 -0
- package/dist/lib/crypto/encrypt.d.ts.map +1 -0
- package/dist/lib/crypto/encrypt.js +24 -0
- package/dist/lib/crypto/encrypt.js.map +1 -0
- package/dist/lib/crypto/index.d.ts +6 -0
- package/dist/lib/crypto/index.d.ts.map +1 -0
- package/dist/lib/crypto/index.js +5 -0
- package/dist/lib/crypto/index.js.map +1 -0
- package/dist/lib/crypto/key-derivation.d.ts +30 -0
- package/dist/lib/crypto/key-derivation.d.ts.map +1 -0
- package/dist/lib/crypto/key-derivation.js +63 -0
- package/dist/lib/crypto/key-derivation.js.map +1 -0
- package/dist/lib/crypto/types.d.ts +22 -0
- package/dist/lib/crypto/types.d.ts.map +1 -0
- package/dist/lib/crypto/types.js +10 -0
- package/dist/lib/crypto/types.js.map +1 -0
- package/dist/lib/storage/database.d.ts +66 -0
- package/dist/lib/storage/database.d.ts.map +1 -0
- package/dist/lib/storage/database.js +195 -0
- package/dist/lib/storage/database.js.map +1 -0
- package/dist/lib/storage/export.d.ts +26 -0
- package/dist/lib/storage/export.d.ts.map +1 -0
- package/dist/lib/storage/export.js +113 -0
- package/dist/lib/storage/export.js.map +1 -0
- package/dist/lib/storage/git.d.ts +16 -0
- package/dist/lib/storage/git.d.ts.map +1 -0
- package/dist/lib/storage/git.js +55 -0
- package/dist/lib/storage/git.js.map +1 -0
- package/dist/lib/storage/index.d.ts +6 -0
- package/dist/lib/storage/index.d.ts.map +1 -0
- package/dist/lib/storage/index.js +5 -0
- package/dist/lib/storage/index.js.map +1 -0
- package/dist/lib/storage/schema.d.ts +17 -0
- package/dist/lib/storage/schema.d.ts.map +1 -0
- package/dist/lib/storage/schema.js +103 -0
- package/dist/lib/storage/schema.js.map +1 -0
- package/dist/lib/storage/types.d.ts +26 -0
- package/dist/lib/storage/types.d.ts.map +1 -0
- package/dist/lib/storage/types.js +2 -0
- package/dist/lib/storage/types.js.map +1 -0
- package/dist/test-helpers.d.ts +12 -30
- package/dist/test-helpers.d.ts.map +1 -1
- package/dist/test-helpers.js +59 -121
- package/dist/test-helpers.js.map +1 -1
- package/dist/types.d.ts +0 -25
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lib/crypto/types.ts"],"names":[],"mappings":"AAkBA;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAwB;IACrD,MAAM,EAAE,KAAK,EAAO,QAAQ;IAC5B,UAAU,EAAE,CAAC;IACb,WAAW,EAAE,CAAC;IACd,SAAS,EAAE,EAAE;CACd,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Evidence } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Evidence database with CRUD operations
|
|
4
|
+
* Manages encrypted evidence storage with SQLite backend
|
|
5
|
+
*/
|
|
6
|
+
export declare class EvidenceDatabase {
|
|
7
|
+
private db;
|
|
8
|
+
/**
|
|
9
|
+
* Creates or opens an evidence database
|
|
10
|
+
* @param dbPath - Path to SQLite database file
|
|
11
|
+
*/
|
|
12
|
+
constructor(dbPath: string);
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new evidence record
|
|
15
|
+
* @param evidence - Evidence data without id, createdAt, updatedAt
|
|
16
|
+
* @returns UUID of created evidence
|
|
17
|
+
*/
|
|
18
|
+
create(evidence: Omit<Evidence, 'id' | 'createdAt' | 'updatedAt'>): string;
|
|
19
|
+
/**
|
|
20
|
+
* Finds evidence by ID
|
|
21
|
+
* @param id - Evidence UUID
|
|
22
|
+
* @returns Evidence or null if not found
|
|
23
|
+
*/
|
|
24
|
+
findById(id: string): Evidence | null;
|
|
25
|
+
/**
|
|
26
|
+
* Finds all evidences for a conversation
|
|
27
|
+
* @param conversationId - Conversation identifier
|
|
28
|
+
* @returns Array of evidences (empty if none found)
|
|
29
|
+
*/
|
|
30
|
+
findByConversationId(conversationId: string): Evidence[];
|
|
31
|
+
/**
|
|
32
|
+
* Lists evidences with pagination
|
|
33
|
+
* @param options - Pagination options (limit, offset)
|
|
34
|
+
* @returns Array of evidences
|
|
35
|
+
*/
|
|
36
|
+
list(options?: {
|
|
37
|
+
limit?: number;
|
|
38
|
+
offset?: number;
|
|
39
|
+
}): Evidence[];
|
|
40
|
+
/**
|
|
41
|
+
* Updates git commit information for an evidence
|
|
42
|
+
* @param id - Evidence UUID
|
|
43
|
+
* @param gitCommitHash - Git commit hash
|
|
44
|
+
* @param gitTimestamp - Git commit timestamp (ISO 8601)
|
|
45
|
+
*/
|
|
46
|
+
updateGitInfo(id: string, gitCommitHash: string, gitTimestamp: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* Adds tags to an evidence (appends to existing tags)
|
|
49
|
+
* @param id - Evidence UUID
|
|
50
|
+
* @param tags - Array of tags to add
|
|
51
|
+
*/
|
|
52
|
+
addTags(id: string, tags: string[]): void;
|
|
53
|
+
/**
|
|
54
|
+
* Closes the database connection
|
|
55
|
+
* Should be called when done with the database
|
|
56
|
+
*/
|
|
57
|
+
close(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Converts database row to Evidence object
|
|
60
|
+
* Handles BLOB to Uint8Array conversion
|
|
61
|
+
* @param row - Raw database row
|
|
62
|
+
* @returns Evidence object
|
|
63
|
+
*/
|
|
64
|
+
private rowToEvidence;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/database.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAqB3C;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,EAAE,CAAoB;IAE9B;;;OAGG;gBACS,MAAM,EAAE,MAAM;IAK1B;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,GAAG,MAAM;IAmC1E;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAkBrC;;;;OAIG;IACH,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,QAAQ,EAAE;IAiBxD;;;;OAIG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,QAAQ,EAAE;IA4B/D;;;;;OAKG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAoB5E;;;;OAIG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI;IA4BzC;;;OAGG;IACH,KAAK,IAAI,IAAI;IAIb;;;;;OAKG;IACH,OAAO,CAAC,aAAa;CAiBtB"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import { createSchema } from './schema.js';
|
|
3
|
+
/**
|
|
4
|
+
* Evidence database with CRUD operations
|
|
5
|
+
* Manages encrypted evidence storage with SQLite backend
|
|
6
|
+
*/
|
|
7
|
+
export class EvidenceDatabase {
|
|
8
|
+
db;
|
|
9
|
+
/**
|
|
10
|
+
* Creates or opens an evidence database
|
|
11
|
+
* @param dbPath - Path to SQLite database file
|
|
12
|
+
*/
|
|
13
|
+
constructor(dbPath) {
|
|
14
|
+
this.db = new Database(dbPath);
|
|
15
|
+
createSchema(this.db);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new evidence record
|
|
19
|
+
* @param evidence - Evidence data without id, createdAt, updatedAt
|
|
20
|
+
* @returns UUID of created evidence
|
|
21
|
+
*/
|
|
22
|
+
create(evidence) {
|
|
23
|
+
const id = crypto.randomUUID();
|
|
24
|
+
const now = new Date().toISOString();
|
|
25
|
+
try {
|
|
26
|
+
const stmt = this.db.prepare(`
|
|
27
|
+
INSERT INTO evidences (
|
|
28
|
+
id, timestamp, conversationId, llmProvider,
|
|
29
|
+
encryptedContent, nonce, contentHash, messageCount,
|
|
30
|
+
gitCommitHash, gitTimestamp, tags, createdAt, updatedAt
|
|
31
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
32
|
+
`);
|
|
33
|
+
stmt.run(id, evidence.timestamp, evidence.conversationId, evidence.llmProvider, Buffer.from(evidence.encryptedContent), Buffer.from(evidence.nonce), evidence.contentHash, evidence.messageCount, evidence.gitCommitHash, evidence.gitTimestamp, evidence.tags, now, now);
|
|
34
|
+
return id;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
throw new Error(`Failed to create evidence: ${error instanceof Error ? error.message : String(error)}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Finds evidence by ID
|
|
42
|
+
* @param id - Evidence UUID
|
|
43
|
+
* @returns Evidence or null if not found
|
|
44
|
+
*/
|
|
45
|
+
findById(id) {
|
|
46
|
+
try {
|
|
47
|
+
const stmt = this.db.prepare(`
|
|
48
|
+
SELECT * FROM evidences WHERE id = ?
|
|
49
|
+
`);
|
|
50
|
+
const row = stmt.get(id);
|
|
51
|
+
if (!row) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
return this.rowToEvidence(row);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
// Don't swallow database errors - re-throw with context
|
|
58
|
+
throw new Error(`Failed to find evidence by ID: ${error instanceof Error ? error.message : String(error)}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Finds all evidences for a conversation
|
|
63
|
+
* @param conversationId - Conversation identifier
|
|
64
|
+
* @returns Array of evidences (empty if none found)
|
|
65
|
+
*/
|
|
66
|
+
findByConversationId(conversationId) {
|
|
67
|
+
try {
|
|
68
|
+
const stmt = this.db.prepare(`
|
|
69
|
+
SELECT * FROM evidences
|
|
70
|
+
WHERE conversationId = ?
|
|
71
|
+
ORDER BY timestamp ASC
|
|
72
|
+
`);
|
|
73
|
+
const rows = stmt.all(conversationId);
|
|
74
|
+
return rows.map((row) => this.rowToEvidence(row));
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
throw new Error(`Failed to find evidences by conversationId: ${error instanceof Error ? error.message : String(error)}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Lists evidences with pagination
|
|
82
|
+
* @param options - Pagination options (limit, offset)
|
|
83
|
+
* @returns Array of evidences
|
|
84
|
+
*/
|
|
85
|
+
list(options) {
|
|
86
|
+
try {
|
|
87
|
+
const limit = options?.limit;
|
|
88
|
+
const offset = options?.offset ?? 0;
|
|
89
|
+
let query = 'SELECT * FROM evidences ORDER BY timestamp DESC';
|
|
90
|
+
const params = [];
|
|
91
|
+
if (limit !== undefined) {
|
|
92
|
+
query += ' LIMIT ?';
|
|
93
|
+
params.push(limit);
|
|
94
|
+
if (offset > 0) {
|
|
95
|
+
query += ' OFFSET ?';
|
|
96
|
+
params.push(offset);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else if (offset > 0) {
|
|
100
|
+
query += ' LIMIT -1 OFFSET ?';
|
|
101
|
+
params.push(offset);
|
|
102
|
+
}
|
|
103
|
+
const stmt = this.db.prepare(query);
|
|
104
|
+
const rows = stmt.all(...params);
|
|
105
|
+
return rows.map((row) => this.rowToEvidence(row));
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw new Error(`Failed to list evidences: ${error instanceof Error ? error.message : String(error)}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Updates git commit information for an evidence
|
|
113
|
+
* @param id - Evidence UUID
|
|
114
|
+
* @param gitCommitHash - Git commit hash
|
|
115
|
+
* @param gitTimestamp - Git commit timestamp (ISO 8601)
|
|
116
|
+
*/
|
|
117
|
+
updateGitInfo(id, gitCommitHash, gitTimestamp) {
|
|
118
|
+
try {
|
|
119
|
+
const stmt = this.db.prepare(`
|
|
120
|
+
UPDATE evidences
|
|
121
|
+
SET gitCommitHash = ?,
|
|
122
|
+
gitTimestamp = ?,
|
|
123
|
+
updatedAt = ?
|
|
124
|
+
WHERE id = ?
|
|
125
|
+
`);
|
|
126
|
+
const result = stmt.run(gitCommitHash, gitTimestamp, new Date().toISOString(), id);
|
|
127
|
+
if (result.changes === 0) {
|
|
128
|
+
throw new Error(`Evidence with id ${id} not found`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
throw new Error(`Failed to update git info: ${error instanceof Error ? error.message : String(error)}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Adds tags to an evidence (appends to existing tags)
|
|
137
|
+
* @param id - Evidence UUID
|
|
138
|
+
* @param tags - Array of tags to add
|
|
139
|
+
*/
|
|
140
|
+
addTags(id, tags) {
|
|
141
|
+
try {
|
|
142
|
+
// First, get existing tags
|
|
143
|
+
const evidence = this.findById(id);
|
|
144
|
+
if (!evidence) {
|
|
145
|
+
throw new Error(`Evidence with id ${id} not found`);
|
|
146
|
+
}
|
|
147
|
+
// Parse existing tags or create empty array
|
|
148
|
+
const existingTags = evidence.tags ? JSON.parse(evidence.tags) : [];
|
|
149
|
+
// Merge tags
|
|
150
|
+
const mergedTags = [...existingTags, ...tags];
|
|
151
|
+
// Update database
|
|
152
|
+
const stmt = this.db.prepare(`
|
|
153
|
+
UPDATE evidences
|
|
154
|
+
SET tags = ?,
|
|
155
|
+
updatedAt = ?
|
|
156
|
+
WHERE id = ?
|
|
157
|
+
`);
|
|
158
|
+
stmt.run(JSON.stringify(mergedTags), new Date().toISOString(), id);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
throw new Error(`Failed to add tags: ${error instanceof Error ? error.message : String(error)}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Closes the database connection
|
|
166
|
+
* Should be called when done with the database
|
|
167
|
+
*/
|
|
168
|
+
close() {
|
|
169
|
+
this.db.close();
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Converts database row to Evidence object
|
|
173
|
+
* Handles BLOB to Uint8Array conversion
|
|
174
|
+
* @param row - Raw database row
|
|
175
|
+
* @returns Evidence object
|
|
176
|
+
*/
|
|
177
|
+
rowToEvidence(row) {
|
|
178
|
+
return {
|
|
179
|
+
id: row.id,
|
|
180
|
+
timestamp: row.timestamp,
|
|
181
|
+
conversationId: row.conversationId,
|
|
182
|
+
llmProvider: row.llmProvider,
|
|
183
|
+
encryptedContent: new Uint8Array(row.encryptedContent),
|
|
184
|
+
nonce: new Uint8Array(row.nonce),
|
|
185
|
+
contentHash: row.contentHash,
|
|
186
|
+
messageCount: row.messageCount,
|
|
187
|
+
gitCommitHash: row.gitCommitHash,
|
|
188
|
+
gitTimestamp: row.gitTimestamp,
|
|
189
|
+
tags: row.tags,
|
|
190
|
+
createdAt: row.createdAt,
|
|
191
|
+
updatedAt: row.updatedAt
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../../src/lib/storage/database.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { EvidenceDatabase } from './database.js';
|
|
2
|
+
export interface ExportOptions {
|
|
3
|
+
evidenceIds?: string[];
|
|
4
|
+
includeGitInfo?: boolean;
|
|
5
|
+
password?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ExportResult {
|
|
8
|
+
filename: string;
|
|
9
|
+
zipData: Uint8Array;
|
|
10
|
+
checksum: string;
|
|
11
|
+
evidenceCount: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Export evidences to a ZIP archive with encrypted data and metadata.
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ **Memory Warning**: Entire ZIP is generated in-memory. For large exports
|
|
17
|
+
* (>1000 evidences or >100MB encrypted data), consider exporting in batches
|
|
18
|
+
* to avoid memory exhaustion.
|
|
19
|
+
*
|
|
20
|
+
* @param db - EvidenceDatabase instance
|
|
21
|
+
* @param options - Export options
|
|
22
|
+
* @returns Export result with ZIP data and metadata
|
|
23
|
+
* @throws Error if database operations fail, IDs not found, or ZIP generation fails
|
|
24
|
+
*/
|
|
25
|
+
export declare function exportEvidences(db: EvidenceDatabase, options?: ExportOptions): Promise<ExportResult>;
|
|
26
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/export.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,UAAU,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAYD;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,gBAAgB,EACpB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAiHvB"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import JSZip from 'jszip';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
// Export format version constant
|
|
4
|
+
const EXPORT_FORMAT_VERSION = '1.0.0';
|
|
5
|
+
/**
|
|
6
|
+
* Export evidences to a ZIP archive with encrypted data and metadata.
|
|
7
|
+
*
|
|
8
|
+
* ⚠️ **Memory Warning**: Entire ZIP is generated in-memory. For large exports
|
|
9
|
+
* (>1000 evidences or >100MB encrypted data), consider exporting in batches
|
|
10
|
+
* to avoid memory exhaustion.
|
|
11
|
+
*
|
|
12
|
+
* @param db - EvidenceDatabase instance
|
|
13
|
+
* @param options - Export options
|
|
14
|
+
* @returns Export result with ZIP data and metadata
|
|
15
|
+
* @throws Error if database operations fail, IDs not found, or ZIP generation fails
|
|
16
|
+
*/
|
|
17
|
+
export async function exportEvidences(db, options = {}) {
|
|
18
|
+
try {
|
|
19
|
+
const { evidenceIds, includeGitInfo = false } = options;
|
|
20
|
+
// Get evidences to export - validate IDs if specified
|
|
21
|
+
let evidences;
|
|
22
|
+
if (evidenceIds) {
|
|
23
|
+
// Validate all IDs exist first
|
|
24
|
+
const notFound = evidenceIds.filter(id => !db.findById(id));
|
|
25
|
+
if (notFound.length > 0) {
|
|
26
|
+
throw new Error(`Evidence IDs not found: ${notFound.join(', ')}`);
|
|
27
|
+
}
|
|
28
|
+
evidences = evidenceIds.map(id => db.findById(id));
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
evidences = db.list();
|
|
32
|
+
}
|
|
33
|
+
// Create ZIP archive
|
|
34
|
+
const zip = new JSZip();
|
|
35
|
+
// Add manifest.json
|
|
36
|
+
const manifest = {
|
|
37
|
+
version: EXPORT_FORMAT_VERSION,
|
|
38
|
+
exportDate: new Date().toISOString(),
|
|
39
|
+
evidenceCount: evidences.length,
|
|
40
|
+
includeGitInfo,
|
|
41
|
+
};
|
|
42
|
+
zip.file('manifest.json', JSON.stringify(manifest, null, 2));
|
|
43
|
+
// Add each evidence
|
|
44
|
+
const checksumEntries = [];
|
|
45
|
+
for (const evidence of evidences) {
|
|
46
|
+
const evidenceFolder = `evidences/${evidence.id}`;
|
|
47
|
+
// Add encrypted-data
|
|
48
|
+
zip.file(`${evidenceFolder}/encrypted-data`, evidence.encryptedContent);
|
|
49
|
+
// Calculate checksum for encrypted data
|
|
50
|
+
const dataChecksum = createHash('sha256')
|
|
51
|
+
.update(evidence.encryptedContent)
|
|
52
|
+
.digest('hex');
|
|
53
|
+
checksumEntries.push(`${dataChecksum} ${evidenceFolder}/encrypted-data`);
|
|
54
|
+
// Add metadata.json
|
|
55
|
+
const metadata = {
|
|
56
|
+
id: evidence.id,
|
|
57
|
+
timestamp: evidence.timestamp,
|
|
58
|
+
conversationId: evidence.conversationId,
|
|
59
|
+
llmProvider: evidence.llmProvider,
|
|
60
|
+
contentHash: evidence.contentHash,
|
|
61
|
+
messageCount: evidence.messageCount,
|
|
62
|
+
tags: evidence.tags,
|
|
63
|
+
nonce: Array.from(evidence.nonce), // Convert Uint8Array to array for JSON
|
|
64
|
+
};
|
|
65
|
+
const metadataJson = JSON.stringify(metadata, null, 2);
|
|
66
|
+
zip.file(`${evidenceFolder}/metadata.json`, metadataJson);
|
|
67
|
+
const metadataChecksum = createHash('sha256')
|
|
68
|
+
.update(metadataJson)
|
|
69
|
+
.digest('hex');
|
|
70
|
+
checksumEntries.push(`${metadataChecksum} ${evidenceFolder}/metadata.json`);
|
|
71
|
+
// Add git-info.json if requested and available
|
|
72
|
+
if (includeGitInfo && evidence.gitCommitHash && evidence.gitTimestamp) {
|
|
73
|
+
const gitInfo = {
|
|
74
|
+
gitCommitHash: evidence.gitCommitHash,
|
|
75
|
+
gitTimestamp: evidence.gitTimestamp,
|
|
76
|
+
};
|
|
77
|
+
const gitInfoJson = JSON.stringify(gitInfo, null, 2);
|
|
78
|
+
zip.file(`${evidenceFolder}/git-info.json`, gitInfoJson);
|
|
79
|
+
const gitChecksum = createHash('sha256').update(gitInfoJson).digest('hex');
|
|
80
|
+
checksumEntries.push(`${gitChecksum} ${evidenceFolder}/git-info.json`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Add checksum.txt
|
|
84
|
+
const checksumContent = [
|
|
85
|
+
'SHA-256 Checksums',
|
|
86
|
+
'=================',
|
|
87
|
+
'',
|
|
88
|
+
...checksumEntries,
|
|
89
|
+
].join('\n');
|
|
90
|
+
zip.file('checksum.txt', checksumContent);
|
|
91
|
+
// Generate ZIP data
|
|
92
|
+
const zipData = await zip.generateAsync({
|
|
93
|
+
type: 'uint8array',
|
|
94
|
+
compression: 'DEFLATE',
|
|
95
|
+
compressionOptions: { level: 9 },
|
|
96
|
+
});
|
|
97
|
+
// Calculate ZIP checksum
|
|
98
|
+
const zipChecksum = createHash('sha256').update(zipData).digest('hex');
|
|
99
|
+
// Generate filename
|
|
100
|
+
const timestamp = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
|
|
101
|
+
const filename = `evidence-export-${timestamp}.zip`;
|
|
102
|
+
return {
|
|
103
|
+
filename,
|
|
104
|
+
zipData,
|
|
105
|
+
checksum: zipChecksum,
|
|
106
|
+
evidenceCount: evidences.length,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
throw new Error(`Failed to export evidences: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/lib/storage/export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git commit information
|
|
3
|
+
*/
|
|
4
|
+
export interface GitInfo {
|
|
5
|
+
commitHash: string;
|
|
6
|
+
timestamp: string;
|
|
7
|
+
message?: string;
|
|
8
|
+
author?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get current Git commit information
|
|
12
|
+
* @param dir - Directory path (defaults to process.cwd())
|
|
13
|
+
* @returns GitInfo or null if not a git repository
|
|
14
|
+
*/
|
|
15
|
+
export declare function getCurrentCommit(dir?: string): Promise<GitInfo | null>;
|
|
16
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/git.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAsBD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA+BzB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import git from 'isomorphic-git';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
/**
|
|
5
|
+
* Find git root directory by walking up the directory tree
|
|
6
|
+
* @param startDir - Starting directory
|
|
7
|
+
* @returns Git root directory or null if not found
|
|
8
|
+
*/
|
|
9
|
+
async function findGitRoot(startDir) {
|
|
10
|
+
let currentDir = path.resolve(startDir);
|
|
11
|
+
const root = path.parse(currentDir).root;
|
|
12
|
+
while (currentDir !== root) {
|
|
13
|
+
const gitDir = path.join(currentDir, '.git');
|
|
14
|
+
if (fs.existsSync(gitDir)) {
|
|
15
|
+
return currentDir;
|
|
16
|
+
}
|
|
17
|
+
currentDir = path.dirname(currentDir);
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get current Git commit information
|
|
23
|
+
* @param dir - Directory path (defaults to process.cwd())
|
|
24
|
+
* @returns GitInfo or null if not a git repository
|
|
25
|
+
*/
|
|
26
|
+
export async function getCurrentCommit(dir = process.cwd()) {
|
|
27
|
+
try {
|
|
28
|
+
// Find git root directory
|
|
29
|
+
const gitRoot = await findGitRoot(dir);
|
|
30
|
+
if (!gitRoot) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
// Get current commit SHA
|
|
34
|
+
const commits = await git.log({
|
|
35
|
+
fs,
|
|
36
|
+
dir: gitRoot,
|
|
37
|
+
depth: 1,
|
|
38
|
+
});
|
|
39
|
+
if (commits.length === 0) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const commit = commits[0];
|
|
43
|
+
return {
|
|
44
|
+
commitHash: commit.oid,
|
|
45
|
+
timestamp: new Date(commit.commit.committer.timestamp * 1000).toISOString(),
|
|
46
|
+
message: commit.commit.message,
|
|
47
|
+
author: commit.commit.author.name,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
// Not a git repository or other git error
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/lib/storage/git.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,gBAAgB,CAAC;AACjC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAYxB;;;;GAIG;AACH,KAAK,UAAU,WAAW,CAAC,QAAgB;IACzC,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC;IAEzC,OAAO,UAAU,KAAK,IAAI,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC7C,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,IAAI,CAAC;QACH,0BAA0B;QAC1B,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QAED,yBAAyB;QACzB,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC;YAC5B,EAAE;YACF,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,CAAC;SACT,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAE1B,OAAO;YACL,UAAU,EAAE,MAAM,CAAC,GAAG;YACtB,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;YAC3E,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO;YAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI;SAClC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0CAA0C;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createSchema, verifySchema } from './schema.js';
|
|
2
|
+
export { EvidenceDatabase } from './database.js';
|
|
3
|
+
export type { Evidence, Metadata } from './types.js';
|
|
4
|
+
export { getCurrentCommit, type GitInfo } from './git.js';
|
|
5
|
+
export { exportEvidences, type ExportOptions, type ExportResult } from './export.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAgB,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAyC,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
/**
|
|
3
|
+
* Creates the database schema (tables and indexes)
|
|
4
|
+
* This function is idempotent - safe to run multiple times
|
|
5
|
+
*
|
|
6
|
+
* @param db - SQLite database instance
|
|
7
|
+
*/
|
|
8
|
+
export declare function createSchema(db: Database.Database): void;
|
|
9
|
+
/**
|
|
10
|
+
* Verifies that the database schema is valid
|
|
11
|
+
* Checks for existence of required tables
|
|
12
|
+
*
|
|
13
|
+
* @param db - SQLite database instance
|
|
14
|
+
* @returns true if schema is valid, false otherwise
|
|
15
|
+
*/
|
|
16
|
+
export declare function verifySchema(db: Database.Database): boolean;
|
|
17
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAO3C;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAqDxD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAqC3D"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Current schema version
|
|
3
|
+
*/
|
|
4
|
+
const SCHEMA_VERSION = '1';
|
|
5
|
+
/**
|
|
6
|
+
* Creates the database schema (tables and indexes)
|
|
7
|
+
* This function is idempotent - safe to run multiple times
|
|
8
|
+
*
|
|
9
|
+
* @param db - SQLite database instance
|
|
10
|
+
*/
|
|
11
|
+
export function createSchema(db) {
|
|
12
|
+
try {
|
|
13
|
+
// Create evidences table
|
|
14
|
+
db.exec(`
|
|
15
|
+
CREATE TABLE IF NOT EXISTS evidences (
|
|
16
|
+
id TEXT PRIMARY KEY,
|
|
17
|
+
timestamp TEXT NOT NULL,
|
|
18
|
+
conversationId TEXT NOT NULL,
|
|
19
|
+
llmProvider TEXT NOT NULL,
|
|
20
|
+
encryptedContent BLOB NOT NULL,
|
|
21
|
+
nonce BLOB NOT NULL,
|
|
22
|
+
contentHash TEXT NOT NULL,
|
|
23
|
+
messageCount INTEGER NOT NULL DEFAULT 0,
|
|
24
|
+
gitCommitHash TEXT,
|
|
25
|
+
gitTimestamp TEXT,
|
|
26
|
+
tags TEXT,
|
|
27
|
+
createdAt TEXT NOT NULL DEFAULT (datetime('now')),
|
|
28
|
+
updatedAt TEXT NOT NULL DEFAULT (datetime('now'))
|
|
29
|
+
);
|
|
30
|
+
`);
|
|
31
|
+
// Create metadata table for schema versioning
|
|
32
|
+
db.exec(`
|
|
33
|
+
CREATE TABLE IF NOT EXISTS metadata (
|
|
34
|
+
key TEXT PRIMARY KEY,
|
|
35
|
+
value TEXT NOT NULL
|
|
36
|
+
);
|
|
37
|
+
`);
|
|
38
|
+
// Create indexes for common queries
|
|
39
|
+
db.exec(`
|
|
40
|
+
CREATE INDEX IF NOT EXISTS idx_timestamp ON evidences(timestamp);
|
|
41
|
+
`);
|
|
42
|
+
db.exec(`
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_conversation_id ON evidences(conversationId);
|
|
44
|
+
`);
|
|
45
|
+
db.exec(`
|
|
46
|
+
CREATE INDEX IF NOT EXISTS idx_content_hash ON evidences(contentHash);
|
|
47
|
+
`);
|
|
48
|
+
// Set schema version (use INSERT OR IGNORE to make it idempotent)
|
|
49
|
+
const stmt = db.prepare(`
|
|
50
|
+
INSERT OR IGNORE INTO metadata (key, value)
|
|
51
|
+
VALUES ('schema_version', ?)
|
|
52
|
+
`);
|
|
53
|
+
stmt.run(SCHEMA_VERSION);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
// Clean up database connection on failure to prevent resource leaks
|
|
57
|
+
db.close();
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Verifies that the database schema is valid
|
|
63
|
+
* Checks for existence of required tables
|
|
64
|
+
*
|
|
65
|
+
* @param db - SQLite database instance
|
|
66
|
+
* @returns true if schema is valid, false otherwise
|
|
67
|
+
*/
|
|
68
|
+
export function verifySchema(db) {
|
|
69
|
+
try {
|
|
70
|
+
// Check if evidences table exists
|
|
71
|
+
const evidencesTableInfo = db.pragma('table_info(evidences)');
|
|
72
|
+
if (!evidencesTableInfo || evidencesTableInfo.length === 0) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
// Check if metadata table exists
|
|
76
|
+
const metadataTableInfo = db.pragma('table_info(metadata)');
|
|
77
|
+
if (!metadataTableInfo || metadataTableInfo.length === 0) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
// Verify required columns exist in evidences table
|
|
81
|
+
const evidencesColumns = evidencesTableInfo.map((col) => col.name);
|
|
82
|
+
const requiredColumns = [
|
|
83
|
+
'id',
|
|
84
|
+
'timestamp',
|
|
85
|
+
'encryptedContent',
|
|
86
|
+
'nonce',
|
|
87
|
+
'contentHash',
|
|
88
|
+
'messageCount',
|
|
89
|
+
'createdAt',
|
|
90
|
+
'updatedAt'
|
|
91
|
+
];
|
|
92
|
+
for (const col of requiredColumns) {
|
|
93
|
+
if (!evidencesColumns.includes(col)) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=schema.js.map
|