wyrm-mcp 3.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/LICENSE +667 -0
- package/README.md +384 -0
- package/dist/analytics.d.ts +100 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +368 -0
- package/dist/analytics.js.map +1 -0
- package/dist/auto-orchestrator.d.ts +118 -0
- package/dist/auto-orchestrator.d.ts.map +1 -0
- package/dist/auto-orchestrator.js +325 -0
- package/dist/auto-orchestrator.js.map +1 -0
- package/dist/autoconfig.d.ts +89 -0
- package/dist/autoconfig.d.ts.map +1 -0
- package/dist/autoconfig.js +576 -0
- package/dist/autoconfig.js.map +1 -0
- package/dist/cli.d.ts +148 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +281 -0
- package/dist/cli.js.map +1 -0
- package/dist/cloud-backup.d.ts +100 -0
- package/dist/cloud-backup.d.ts.map +1 -0
- package/dist/cloud-backup.js +545 -0
- package/dist/cloud-backup.js.map +1 -0
- package/dist/crypto.d.ts +72 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +164 -0
- package/dist/crypto.js.map +1 -0
- package/dist/database.d.ts +218 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +1058 -0
- package/dist/database.js.map +1 -0
- package/dist/http-auth.d.ts +68 -0
- package/dist/http-auth.d.ts.map +1 -0
- package/dist/http-auth.js +296 -0
- package/dist/http-auth.js.map +1 -0
- package/dist/http-fast.d.ts +13 -0
- package/dist/http-fast.d.ts.map +1 -0
- package/dist/http-fast.js +325 -0
- package/dist/http-fast.js.map +1 -0
- package/dist/http-server.d.ts +12 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +383 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1695 -0
- package/dist/index.js.map +1 -0
- package/dist/license.d.ts +177 -0
- package/dist/license.d.ts.map +1 -0
- package/dist/license.js +405 -0
- package/dist/license.js.map +1 -0
- package/dist/logger.d.ts +76 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +195 -0
- package/dist/logger.js.map +1 -0
- package/dist/performance.d.ts +114 -0
- package/dist/performance.d.ts.map +1 -0
- package/dist/performance.js +228 -0
- package/dist/performance.js.map +1 -0
- package/dist/resilience.d.ts +146 -0
- package/dist/resilience.d.ts.map +1 -0
- package/dist/resilience.js +563 -0
- package/dist/resilience.js.map +1 -0
- package/dist/security.d.ts +68 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +215 -0
- package/dist/security.js.map +1 -0
- package/dist/setup.d.ts +21 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +261 -0
- package/dist/setup.js.map +1 -0
- package/dist/summarizer.d.ts +30 -0
- package/dist/summarizer.d.ts.map +1 -0
- package/dist/summarizer.js +139 -0
- package/dist/summarizer.js.map +1 -0
- package/dist/sync.d.ts +39 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +356 -0
- package/dist/sync.js.map +1 -0
- package/dist/types.d.ts +267 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +30 -0
- package/dist/types.js.map +1 -0
- package/dist/vectors.d.ts +103 -0
- package/dist/vectors.d.ts.map +1 -0
- package/dist/vectors.js +311 -0
- package/dist/vectors.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wyrm Cloud Backup — Encrypted backup/restore to Cloudflare R2
|
|
3
|
+
*
|
|
4
|
+
* @copyright 2026 Ghost Protocol (Pvt) Ltd. All Rights Reserved.
|
|
5
|
+
* @license Proprietary - See LICENSE file for details.
|
|
6
|
+
* @module cloud-backup
|
|
7
|
+
* @version 3.2.0
|
|
8
|
+
*/
|
|
9
|
+
import { createReadStream, createWriteStream, statSync, existsSync, copyFileSync, unlinkSync, readFileSync, writeFileSync, renameSync } from 'fs';
|
|
10
|
+
import { createGzip, gunzipSync } from 'zlib';
|
|
11
|
+
import { pipeline } from 'stream/promises';
|
|
12
|
+
import { createCipheriv, createDecipheriv, randomBytes, scryptSync, createHash, createHmac } from 'crypto';
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
import { hostname, platform, arch, cpus } from 'os';
|
|
15
|
+
// ==================== CONSTANTS ====================
|
|
16
|
+
const WYRM_VERSION = '3.2.0';
|
|
17
|
+
const BACKUP_FORMAT_VERSION = 1;
|
|
18
|
+
const ALGORITHM = 'aes-256-gcm';
|
|
19
|
+
const IV_LENGTH = 16;
|
|
20
|
+
const SALT_LENGTH = 32;
|
|
21
|
+
const TAG_LENGTH = 16;
|
|
22
|
+
const KEY_LENGTH = 32;
|
|
23
|
+
const DEFAULT_KEEP_COUNT = 10;
|
|
24
|
+
// ==================== BUFFER ENCRYPTION ====================
|
|
25
|
+
/**
|
|
26
|
+
* Encrypt a buffer with AES-256-GCM using a password.
|
|
27
|
+
* Output format: [16-byte IV][32-byte salt][16-byte auth tag][encrypted data]
|
|
28
|
+
*/
|
|
29
|
+
function encryptBuffer(data, password) {
|
|
30
|
+
const iv = randomBytes(IV_LENGTH);
|
|
31
|
+
const salt = randomBytes(SALT_LENGTH);
|
|
32
|
+
const key = scryptSync(password, salt, KEY_LENGTH);
|
|
33
|
+
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
34
|
+
const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
|
|
35
|
+
const tag = cipher.getAuthTag();
|
|
36
|
+
// Header: IV + salt + auth tag + ciphertext
|
|
37
|
+
return Buffer.concat([iv, salt, tag, encrypted]);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Decrypt a buffer encrypted by encryptBuffer.
|
|
41
|
+
* Parses the [IV][salt][tag][data] header, derives key, decrypts.
|
|
42
|
+
*/
|
|
43
|
+
function decryptBuffer(encrypted, password) {
|
|
44
|
+
const headerSize = IV_LENGTH + SALT_LENGTH + TAG_LENGTH;
|
|
45
|
+
if (encrypted.length < headerSize) {
|
|
46
|
+
throw new Error('Encrypted data too short — corrupted or not a Wyrm backup');
|
|
47
|
+
}
|
|
48
|
+
let offset = 0;
|
|
49
|
+
const iv = encrypted.subarray(offset, offset += IV_LENGTH);
|
|
50
|
+
const salt = encrypted.subarray(offset, offset += SALT_LENGTH);
|
|
51
|
+
const tag = encrypted.subarray(offset, offset += TAG_LENGTH);
|
|
52
|
+
const data = encrypted.subarray(offset);
|
|
53
|
+
const key = scryptSync(password, salt, KEY_LENGTH);
|
|
54
|
+
const decipher = createDecipheriv(ALGORITHM, key, iv);
|
|
55
|
+
decipher.setAuthTag(tag);
|
|
56
|
+
try {
|
|
57
|
+
return Buffer.concat([decipher.update(data), decipher.final()]);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
throw new Error('Decryption failed — wrong password or corrupted backup');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// ==================== MINIMAL S3-COMPATIBLE CLIENT ====================
|
|
64
|
+
/**
|
|
65
|
+
* Minimal S3-compatible client for Cloudflare R2.
|
|
66
|
+
* Uses AWS Signature V4 signing with Node.js built-ins only — zero dependencies.
|
|
67
|
+
*/
|
|
68
|
+
class S3Client {
|
|
69
|
+
accessKeyId;
|
|
70
|
+
secretAccessKey;
|
|
71
|
+
region;
|
|
72
|
+
endpoint;
|
|
73
|
+
bucket;
|
|
74
|
+
host;
|
|
75
|
+
constructor(config) {
|
|
76
|
+
this.accessKeyId = config.accessKeyId;
|
|
77
|
+
this.secretAccessKey = config.secretAccessKey;
|
|
78
|
+
this.region = config.region ?? 'auto';
|
|
79
|
+
this.endpoint = config.endpoint.replace(/\/$/, '');
|
|
80
|
+
this.bucket = config.bucket;
|
|
81
|
+
// Extract host from endpoint
|
|
82
|
+
const url = new URL(this.endpoint);
|
|
83
|
+
this.host = url.host;
|
|
84
|
+
}
|
|
85
|
+
/** PUT an object to the bucket */
|
|
86
|
+
async putObject(key, body, contentType = 'application/octet-stream') {
|
|
87
|
+
const path = `/${this.bucket}/${encodeS3Key(key)}`;
|
|
88
|
+
const headers = {
|
|
89
|
+
'Content-Type': contentType,
|
|
90
|
+
'Content-Length': body.length.toString(),
|
|
91
|
+
};
|
|
92
|
+
const signed = this.signRequest('PUT', path, headers, body);
|
|
93
|
+
const res = await fetch(`${this.endpoint}${path}`, {
|
|
94
|
+
method: 'PUT',
|
|
95
|
+
headers: signed,
|
|
96
|
+
body: body,
|
|
97
|
+
});
|
|
98
|
+
if (!res.ok) {
|
|
99
|
+
const text = await res.text();
|
|
100
|
+
throw new Error(`S3 PUT failed (${res.status}): ${text}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** GET an object from the bucket */
|
|
104
|
+
async getObject(key) {
|
|
105
|
+
const path = `/${this.bucket}/${encodeS3Key(key)}`;
|
|
106
|
+
const headers = {};
|
|
107
|
+
const signed = this.signRequest('GET', path, headers);
|
|
108
|
+
const res = await fetch(`${this.endpoint}${path}`, {
|
|
109
|
+
method: 'GET',
|
|
110
|
+
headers: signed,
|
|
111
|
+
});
|
|
112
|
+
if (!res.ok) {
|
|
113
|
+
const text = await res.text();
|
|
114
|
+
throw new Error(`S3 GET failed (${res.status}): ${text}`);
|
|
115
|
+
}
|
|
116
|
+
const arrayBuf = await res.arrayBuffer();
|
|
117
|
+
return Buffer.from(arrayBuf);
|
|
118
|
+
}
|
|
119
|
+
/** LIST objects with a given prefix */
|
|
120
|
+
async listObjects(prefix) {
|
|
121
|
+
const results = [];
|
|
122
|
+
let continuationToken;
|
|
123
|
+
do {
|
|
124
|
+
const params = new URLSearchParams({
|
|
125
|
+
'list-type': '2',
|
|
126
|
+
prefix,
|
|
127
|
+
});
|
|
128
|
+
if (continuationToken) {
|
|
129
|
+
params.set('continuation-token', continuationToken);
|
|
130
|
+
}
|
|
131
|
+
const path = `/${this.bucket}?${params.toString()}`;
|
|
132
|
+
const headers = {};
|
|
133
|
+
const signed = this.signRequest('GET', path, headers);
|
|
134
|
+
const res = await fetch(`${this.endpoint}${path}`, {
|
|
135
|
+
method: 'GET',
|
|
136
|
+
headers: signed,
|
|
137
|
+
});
|
|
138
|
+
if (!res.ok) {
|
|
139
|
+
const text = await res.text();
|
|
140
|
+
throw new Error(`S3 LIST failed (${res.status}): ${text}`);
|
|
141
|
+
}
|
|
142
|
+
const xml = await res.text();
|
|
143
|
+
results.push(...parseListXml(xml));
|
|
144
|
+
// Check for truncation / pagination
|
|
145
|
+
const truncatedMatch = xml.match(/<IsTruncated>(.*?)<\/IsTruncated>/);
|
|
146
|
+
const isTruncated = truncatedMatch?.[1] === 'true';
|
|
147
|
+
if (isTruncated) {
|
|
148
|
+
const tokenMatch = xml.match(/<NextContinuationToken>(.*?)<\/NextContinuationToken>/);
|
|
149
|
+
continuationToken = tokenMatch?.[1];
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
continuationToken = undefined;
|
|
153
|
+
}
|
|
154
|
+
} while (continuationToken);
|
|
155
|
+
return results;
|
|
156
|
+
}
|
|
157
|
+
/** DELETE an object from the bucket */
|
|
158
|
+
async deleteObject(key) {
|
|
159
|
+
const path = `/${this.bucket}/${encodeS3Key(key)}`;
|
|
160
|
+
const headers = {};
|
|
161
|
+
const signed = this.signRequest('DELETE', path, headers);
|
|
162
|
+
const res = await fetch(`${this.endpoint}${path}`, {
|
|
163
|
+
method: 'DELETE',
|
|
164
|
+
headers: signed,
|
|
165
|
+
});
|
|
166
|
+
if (!res.ok) {
|
|
167
|
+
const text = await res.text();
|
|
168
|
+
throw new Error(`S3 DELETE failed (${res.status}): ${text}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Generate AWS Signature V4 headers.
|
|
173
|
+
* Implements the full signing flow:
|
|
174
|
+
* 1. Canonical request
|
|
175
|
+
* 2. String to sign
|
|
176
|
+
* 3. Signing key derivation
|
|
177
|
+
* 4. Authorization header
|
|
178
|
+
*/
|
|
179
|
+
signRequest(method, path, headers, body) {
|
|
180
|
+
const now = new Date();
|
|
181
|
+
const dateStamp = toDateStamp(now); // YYYYMMDD
|
|
182
|
+
const amzDate = toAmzDate(now); // YYYYMMDD'T'HHMMSS'Z'
|
|
183
|
+
// Split path and query string
|
|
184
|
+
const [canonicalUri, queryString] = splitPathQuery(path);
|
|
185
|
+
// Required headers
|
|
186
|
+
headers['host'] = this.host;
|
|
187
|
+
headers['x-amz-date'] = amzDate;
|
|
188
|
+
headers['x-amz-content-sha256'] = sha256Hex(body ?? Buffer.alloc(0));
|
|
189
|
+
// 1. Canonical request
|
|
190
|
+
const signedHeaderKeys = Object.keys(headers)
|
|
191
|
+
.map(k => k.toLowerCase())
|
|
192
|
+
.sort();
|
|
193
|
+
const canonicalHeaders = signedHeaderKeys
|
|
194
|
+
.map(k => `${k}:${headers[Object.keys(headers).find(h => h.toLowerCase() === k)].trim()}`)
|
|
195
|
+
.join('\n') + '\n';
|
|
196
|
+
const signedHeaders = signedHeaderKeys.join(';');
|
|
197
|
+
const canonicalRequest = [
|
|
198
|
+
method,
|
|
199
|
+
canonicalUri,
|
|
200
|
+
normalizeQueryString(queryString),
|
|
201
|
+
canonicalHeaders,
|
|
202
|
+
signedHeaders,
|
|
203
|
+
headers['x-amz-content-sha256'],
|
|
204
|
+
].join('\n');
|
|
205
|
+
// 2. String to sign
|
|
206
|
+
const credentialScope = `${dateStamp}/${this.region}/s3/aws4_request`;
|
|
207
|
+
const stringToSign = [
|
|
208
|
+
'AWS4-HMAC-SHA256',
|
|
209
|
+
amzDate,
|
|
210
|
+
credentialScope,
|
|
211
|
+
sha256Hex(Buffer.from(canonicalRequest, 'utf-8')),
|
|
212
|
+
].join('\n');
|
|
213
|
+
// 3. Signing key
|
|
214
|
+
const signingKey = deriveSigningKey(this.secretAccessKey, dateStamp, this.region, 's3');
|
|
215
|
+
// 4. Signature
|
|
216
|
+
const signature = hmacHex(signingKey, stringToSign);
|
|
217
|
+
// 5. Authorization header
|
|
218
|
+
headers['Authorization'] =
|
|
219
|
+
`AWS4-HMAC-SHA256 Credential=${this.accessKeyId}/${credentialScope}, ` +
|
|
220
|
+
`SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
|
221
|
+
return headers;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// ==================== S3 SIGNING HELPERS ====================
|
|
225
|
+
function toDateStamp(date) {
|
|
226
|
+
return date.toISOString().replace(/[-:T]/g, '').slice(0, 8);
|
|
227
|
+
}
|
|
228
|
+
function toAmzDate(date) {
|
|
229
|
+
return date.toISOString().replace(/[-:]/g, '').replace(/\.\d{3}/, '');
|
|
230
|
+
}
|
|
231
|
+
function sha256Hex(data) {
|
|
232
|
+
return createHash('sha256').update(data).digest('hex');
|
|
233
|
+
}
|
|
234
|
+
function hmac(key, data) {
|
|
235
|
+
return createHmac('sha256', key).update(data, 'utf-8').digest();
|
|
236
|
+
}
|
|
237
|
+
function hmacHex(key, data) {
|
|
238
|
+
return createHmac('sha256', key).update(data, 'utf-8').digest('hex');
|
|
239
|
+
}
|
|
240
|
+
function deriveSigningKey(secret, dateStamp, region, service) {
|
|
241
|
+
let key = hmac(`AWS4${secret}`, dateStamp);
|
|
242
|
+
key = hmac(key, region);
|
|
243
|
+
key = hmac(key, service);
|
|
244
|
+
key = hmac(key, 'aws4_request');
|
|
245
|
+
return key;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Encode an S3 key — URI-encode each path segment individually,
|
|
249
|
+
* preserving `/` separators.
|
|
250
|
+
*/
|
|
251
|
+
function encodeS3Key(key) {
|
|
252
|
+
return key
|
|
253
|
+
.split('/')
|
|
254
|
+
.map(segment => encodeURIComponent(segment))
|
|
255
|
+
.join('/');
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Split a path into canonical URI and query string.
|
|
259
|
+
* e.g. "/bucket?list-type=2&prefix=x" → ["/bucket", "list-type=2&prefix=x"]
|
|
260
|
+
*/
|
|
261
|
+
function splitPathQuery(path) {
|
|
262
|
+
const idx = path.indexOf('?');
|
|
263
|
+
if (idx === -1)
|
|
264
|
+
return [path, ''];
|
|
265
|
+
return [path.slice(0, idx), path.slice(idx + 1)];
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Normalize a query string for canonical request:
|
|
269
|
+
* sort by parameter name, then by value.
|
|
270
|
+
*/
|
|
271
|
+
function normalizeQueryString(qs) {
|
|
272
|
+
if (!qs)
|
|
273
|
+
return '';
|
|
274
|
+
return qs
|
|
275
|
+
.split('&')
|
|
276
|
+
.map(pair => {
|
|
277
|
+
const [k, v] = pair.split('=');
|
|
278
|
+
return `${encodeURIComponent(decodeURIComponent(k))}=${encodeURIComponent(decodeURIComponent(v ?? ''))}`;
|
|
279
|
+
})
|
|
280
|
+
.sort()
|
|
281
|
+
.join('&');
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Parse the XML response from S3 ListObjectsV2.
|
|
285
|
+
* Extracts <Key>, <Size>, <LastModified> from each <Contents> block.
|
|
286
|
+
*/
|
|
287
|
+
function parseListXml(xml) {
|
|
288
|
+
const results = [];
|
|
289
|
+
const contentsRegex = /<Contents>([\s\S]*?)<\/Contents>/g;
|
|
290
|
+
let match;
|
|
291
|
+
while ((match = contentsRegex.exec(xml)) !== null) {
|
|
292
|
+
const block = match[1];
|
|
293
|
+
const key = block.match(/<Key>(.*?)<\/Key>/)?.[1] ?? '';
|
|
294
|
+
const size = parseInt(block.match(/<Size>(.*?)<\/Size>/)?.[1] ?? '0', 10);
|
|
295
|
+
const lastModified = block.match(/<LastModified>(.*?)<\/LastModified>/)?.[1] ?? '';
|
|
296
|
+
results.push({ key, size, lastModified });
|
|
297
|
+
}
|
|
298
|
+
return results;
|
|
299
|
+
}
|
|
300
|
+
// ==================== WYRM CLOUD BACKUP ====================
|
|
301
|
+
export class WyrmCloudBackup {
|
|
302
|
+
config = null;
|
|
303
|
+
encryptionKey = null;
|
|
304
|
+
s3 = null;
|
|
305
|
+
constructor() { }
|
|
306
|
+
/** Configure cloud storage credentials and optional encryption key */
|
|
307
|
+
configure(config, encryptionKey) {
|
|
308
|
+
if (!config.endpoint || !config.bucket || !config.accessKeyId || !config.secretAccessKey) {
|
|
309
|
+
throw new Error('Cloud config requires endpoint, bucket, accessKeyId, and secretAccessKey');
|
|
310
|
+
}
|
|
311
|
+
this.config = {
|
|
312
|
+
...config,
|
|
313
|
+
region: config.region ?? 'auto',
|
|
314
|
+
};
|
|
315
|
+
this.encryptionKey = encryptionKey ?? null;
|
|
316
|
+
this.s3 = new S3Client(this.config);
|
|
317
|
+
}
|
|
318
|
+
/** Check if cloud backup is configured */
|
|
319
|
+
isConfigured() {
|
|
320
|
+
return this.config !== null && this.s3 !== null;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Backup: SQLite DB → gzip → AES-256-GCM encrypt → upload to R2
|
|
324
|
+
*
|
|
325
|
+
* Pipeline:
|
|
326
|
+
* 1. Copy SQLite file to a temp snapshot (safe point-in-time copy)
|
|
327
|
+
* 2. Gzip compress
|
|
328
|
+
* 3. If encryption key set: AES-256-GCM encrypt the gzipped blob
|
|
329
|
+
* 4. Upload encrypted/compressed blob to R2
|
|
330
|
+
* 5. Upload metadata JSON alongside
|
|
331
|
+
* 6. Clean up temp files
|
|
332
|
+
*
|
|
333
|
+
* Key format: backups/{machine_id}/{YYYY-MM-DD_HHmmss}.wyrm.bak
|
|
334
|
+
*/
|
|
335
|
+
async backup(dbPath) {
|
|
336
|
+
this.assertConfigured();
|
|
337
|
+
if (!existsSync(dbPath)) {
|
|
338
|
+
throw new Error(`Database not found: ${dbPath}`);
|
|
339
|
+
}
|
|
340
|
+
const dbStat = statSync(dbPath);
|
|
341
|
+
const machineId = this.getMachineId();
|
|
342
|
+
const now = new Date();
|
|
343
|
+
const timestamp = formatTimestamp(now);
|
|
344
|
+
const backupKey = `backups/${machineId}/${timestamp}.wyrm.bak`;
|
|
345
|
+
const metadataKey = `backups/${machineId}/${timestamp}.wyrm.meta.json`;
|
|
346
|
+
// Temp files in the same directory as the DB to avoid cross-device issues
|
|
347
|
+
const dbDir = join(dbPath, '..');
|
|
348
|
+
const tempCopy = join(dbDir, `.wyrm-backup-${Date.now()}.tmp`);
|
|
349
|
+
const tempGz = join(dbDir, `.wyrm-backup-${Date.now()}.gz.tmp`);
|
|
350
|
+
try {
|
|
351
|
+
// 1. Safe snapshot — copy the database file
|
|
352
|
+
copyFileSync(dbPath, tempCopy);
|
|
353
|
+
// Also copy WAL/SHM if they exist (for consistency)
|
|
354
|
+
const walPath = `${dbPath}-wal`;
|
|
355
|
+
const shmPath = `${dbPath}-shm`;
|
|
356
|
+
if (existsSync(walPath))
|
|
357
|
+
copyFileSync(walPath, `${tempCopy}-wal`);
|
|
358
|
+
if (existsSync(shmPath))
|
|
359
|
+
copyFileSync(shmPath, `${tempCopy}-shm`);
|
|
360
|
+
// 2. Gzip compress
|
|
361
|
+
await pipeline(createReadStream(tempCopy), createGzip({ level: 9 }), createWriteStream(tempGz));
|
|
362
|
+
let uploadPayload = Buffer.from(readFileSync(tempGz));
|
|
363
|
+
const compressedSize = uploadPayload.length;
|
|
364
|
+
// 3. Encrypt if key is set
|
|
365
|
+
const isEncrypted = this.encryptionKey !== null;
|
|
366
|
+
if (isEncrypted) {
|
|
367
|
+
uploadPayload = encryptBuffer(uploadPayload, this.encryptionKey);
|
|
368
|
+
}
|
|
369
|
+
// Compute checksum of final payload
|
|
370
|
+
const checksum = sha256Hex(uploadPayload);
|
|
371
|
+
// 4. Upload blob
|
|
372
|
+
await this.s3.putObject(backupKey, uploadPayload, 'application/x-wyrm-backup');
|
|
373
|
+
// 5. Build and upload metadata
|
|
374
|
+
const metadata = {
|
|
375
|
+
version: BACKUP_FORMAT_VERSION,
|
|
376
|
+
wyrm_version: WYRM_VERSION,
|
|
377
|
+
timestamp: now.toISOString(),
|
|
378
|
+
db_size: dbStat.size,
|
|
379
|
+
compressed_size: compressedSize,
|
|
380
|
+
encrypted: isEncrypted,
|
|
381
|
+
machine_id: machineId,
|
|
382
|
+
checksum,
|
|
383
|
+
};
|
|
384
|
+
await this.s3.putObject(metadataKey, Buffer.from(JSON.stringify(metadata, null, 2), 'utf-8'), 'application/json');
|
|
385
|
+
return { key: backupKey, metadata };
|
|
386
|
+
}
|
|
387
|
+
finally {
|
|
388
|
+
// 6. Clean up temp files
|
|
389
|
+
safeUnlink(tempCopy);
|
|
390
|
+
safeUnlink(tempGz);
|
|
391
|
+
safeUnlink(`${tempCopy}-wal`);
|
|
392
|
+
safeUnlink(`${tempCopy}-shm`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* List available backups for this machine, sorted newest-first.
|
|
397
|
+
* Fetches metadata JSON for each backup.
|
|
398
|
+
*/
|
|
399
|
+
async listBackups() {
|
|
400
|
+
this.assertConfigured();
|
|
401
|
+
const machineId = this.getMachineId();
|
|
402
|
+
const prefix = `backups/${machineId}/`;
|
|
403
|
+
const objects = await this.s3.listObjects(prefix);
|
|
404
|
+
// Find metadata files
|
|
405
|
+
const metaObjects = objects.filter(o => o.key.endsWith('.wyrm.meta.json'));
|
|
406
|
+
const metadataList = [];
|
|
407
|
+
for (const obj of metaObjects) {
|
|
408
|
+
try {
|
|
409
|
+
const buf = await this.s3.getObject(obj.key);
|
|
410
|
+
const meta = JSON.parse(buf.toString('utf-8'));
|
|
411
|
+
metadataList.push(meta);
|
|
412
|
+
}
|
|
413
|
+
catch {
|
|
414
|
+
// Skip unreadable metadata
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
// Sort newest first
|
|
418
|
+
metadataList.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
419
|
+
return metadataList;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Restore: Download from R2 → decrypt → gunzip → write to target path.
|
|
423
|
+
*
|
|
424
|
+
* If the target file already exists, it is renamed to `{target}.bak` before overwriting.
|
|
425
|
+
* Verifies checksum of the downloaded blob against metadata.
|
|
426
|
+
*/
|
|
427
|
+
async restore(backupKey, targetPath) {
|
|
428
|
+
this.assertConfigured();
|
|
429
|
+
// Derive metadata key from backup key
|
|
430
|
+
const metadataKey = backupKey.replace(/\.wyrm\.bak$/, '.wyrm.meta.json');
|
|
431
|
+
// Download metadata
|
|
432
|
+
let metadata;
|
|
433
|
+
try {
|
|
434
|
+
const metaBuf = await this.s3.getObject(metadataKey);
|
|
435
|
+
metadata = JSON.parse(metaBuf.toString('utf-8'));
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
throw new Error(`Backup metadata not found for key: ${backupKey}`);
|
|
439
|
+
}
|
|
440
|
+
// 1. Download encrypted blob
|
|
441
|
+
let blob = await this.s3.getObject(backupKey);
|
|
442
|
+
// 5. Verify checksum
|
|
443
|
+
const actualChecksum = sha256Hex(blob);
|
|
444
|
+
if (actualChecksum !== metadata.checksum) {
|
|
445
|
+
throw new Error(`Checksum mismatch — backup may be corrupted. ` +
|
|
446
|
+
`Expected: ${metadata.checksum}, Got: ${actualChecksum}`);
|
|
447
|
+
}
|
|
448
|
+
// 2. Decrypt if encrypted
|
|
449
|
+
if (metadata.encrypted) {
|
|
450
|
+
if (!this.encryptionKey) {
|
|
451
|
+
throw new Error('Backup is encrypted but no encryption key is configured');
|
|
452
|
+
}
|
|
453
|
+
blob = decryptBuffer(blob, this.encryptionKey);
|
|
454
|
+
}
|
|
455
|
+
// 3. Gunzip decompress
|
|
456
|
+
const decompressed = gunzipSync(blob);
|
|
457
|
+
// 4. Write to targetPath (back up existing file first)
|
|
458
|
+
if (existsSync(targetPath)) {
|
|
459
|
+
const bakPath = `${targetPath}.bak`;
|
|
460
|
+
renameSync(targetPath, bakPath);
|
|
461
|
+
}
|
|
462
|
+
writeFileSync(targetPath, decompressed);
|
|
463
|
+
return { restored: true, size: decompressed.length };
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Delete old backups, keeping the most recent `keepCount`.
|
|
467
|
+
* Deletes both the .wyrm.bak blob and its .wyrm.meta.json sidecar.
|
|
468
|
+
*/
|
|
469
|
+
async pruneBackups(keepCount = DEFAULT_KEEP_COUNT) {
|
|
470
|
+
this.assertConfigured();
|
|
471
|
+
const machineId = this.getMachineId();
|
|
472
|
+
const prefix = `backups/${machineId}/`;
|
|
473
|
+
const objects = await this.s3.listObjects(prefix);
|
|
474
|
+
// Pair backup blobs with their metadata by timestamp stem
|
|
475
|
+
const backupBlobs = objects
|
|
476
|
+
.filter(o => o.key.endsWith('.wyrm.bak'))
|
|
477
|
+
.sort((a, b) => b.lastModified.localeCompare(a.lastModified)); // newest first
|
|
478
|
+
if (backupBlobs.length <= keepCount) {
|
|
479
|
+
return { deleted: 0 };
|
|
480
|
+
}
|
|
481
|
+
const toDelete = backupBlobs.slice(keepCount);
|
|
482
|
+
let deleted = 0;
|
|
483
|
+
for (const obj of toDelete) {
|
|
484
|
+
const metaKey = obj.key.replace(/\.wyrm\.bak$/, '.wyrm.meta.json');
|
|
485
|
+
try {
|
|
486
|
+
await this.s3.deleteObject(obj.key);
|
|
487
|
+
deleted++;
|
|
488
|
+
}
|
|
489
|
+
catch {
|
|
490
|
+
// Best-effort deletion
|
|
491
|
+
}
|
|
492
|
+
try {
|
|
493
|
+
await this.s3.deleteObject(metaKey);
|
|
494
|
+
}
|
|
495
|
+
catch {
|
|
496
|
+
// Metadata may not exist
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return { deleted };
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Get a deterministic machine fingerprint for device tracking.
|
|
503
|
+
* Hash of: hostname + platform + arch + first CPU model.
|
|
504
|
+
* Stable across reboots, unique per machine.
|
|
505
|
+
*/
|
|
506
|
+
getMachineId() {
|
|
507
|
+
const parts = [
|
|
508
|
+
hostname(),
|
|
509
|
+
platform(),
|
|
510
|
+
arch(),
|
|
511
|
+
cpus()[0]?.model ?? 'unknown-cpu',
|
|
512
|
+
].join('|');
|
|
513
|
+
return createHash('sha256').update(parts).digest('hex').slice(0, 16);
|
|
514
|
+
}
|
|
515
|
+
/** Throw if not configured */
|
|
516
|
+
assertConfigured() {
|
|
517
|
+
if (!this.isConfigured()) {
|
|
518
|
+
throw new Error('Cloud backup not configured. Call configure() with R2 credentials first.');
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
// ==================== HELPERS ====================
|
|
523
|
+
/** Format a Date as YYYY-MM-DD_HHmmss */
|
|
524
|
+
function formatTimestamp(date) {
|
|
525
|
+
const y = date.getUTCFullYear();
|
|
526
|
+
const mo = String(date.getUTCMonth() + 1).padStart(2, '0');
|
|
527
|
+
const d = String(date.getUTCDate()).padStart(2, '0');
|
|
528
|
+
const h = String(date.getUTCHours()).padStart(2, '0');
|
|
529
|
+
const mi = String(date.getUTCMinutes()).padStart(2, '0');
|
|
530
|
+
const s = String(date.getUTCSeconds()).padStart(2, '0');
|
|
531
|
+
return `${y}-${mo}-${d}_${h}${mi}${s}`;
|
|
532
|
+
}
|
|
533
|
+
/** Unlink a file if it exists, swallowing errors */
|
|
534
|
+
function safeUnlink(path) {
|
|
535
|
+
try {
|
|
536
|
+
if (existsSync(path))
|
|
537
|
+
unlinkSync(path);
|
|
538
|
+
}
|
|
539
|
+
catch {
|
|
540
|
+
// best-effort cleanup
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
// ==================== EXPORTS ====================
|
|
544
|
+
export { encryptBuffer, decryptBuffer };
|
|
545
|
+
//# sourceMappingURL=cloud-backup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloud-backup.js","sourceRoot":"","sources":["../src/cloud-backup.ts"],"names":[],"mappings":"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"}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wyrm Encryption Module
|
|
3
|
+
* AES-256-GCM encryption for sensitive memory data
|
|
4
|
+
*
|
|
5
|
+
* @copyright 2026 Ghost Protocol (Pvt) Ltd. All Rights Reserved.
|
|
6
|
+
* @license Proprietary - See LICENSE file for details.
|
|
7
|
+
* @module crypto
|
|
8
|
+
* @version 3.0.0
|
|
9
|
+
*/
|
|
10
|
+
export interface EncryptedData {
|
|
11
|
+
iv: string;
|
|
12
|
+
salt: string;
|
|
13
|
+
tag: string;
|
|
14
|
+
data: string;
|
|
15
|
+
version: number;
|
|
16
|
+
}
|
|
17
|
+
export interface CryptoConfig {
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
keyDerivation: 'scrypt' | 'pbkdf2';
|
|
20
|
+
iterations?: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Wyrm Crypto - Handles encryption/decryption of sensitive data
|
|
24
|
+
*/
|
|
25
|
+
export declare class WyrmCrypto {
|
|
26
|
+
private masterKey;
|
|
27
|
+
private config;
|
|
28
|
+
constructor(config?: Partial<CryptoConfig>);
|
|
29
|
+
/**
|
|
30
|
+
* Initialize crypto with a master password
|
|
31
|
+
*/
|
|
32
|
+
initialize(password: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Check if encryption is enabled and configured
|
|
35
|
+
*/
|
|
36
|
+
isEnabled(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Derive a unique key for each piece of data
|
|
39
|
+
*/
|
|
40
|
+
private deriveKey;
|
|
41
|
+
/**
|
|
42
|
+
* Encrypt a string value
|
|
43
|
+
*/
|
|
44
|
+
encrypt(plaintext: string): EncryptedData;
|
|
45
|
+
/**
|
|
46
|
+
* Decrypt an encrypted value
|
|
47
|
+
*/
|
|
48
|
+
decrypt(encrypted: EncryptedData): string;
|
|
49
|
+
/**
|
|
50
|
+
* Encrypt if enabled, otherwise return plaintext
|
|
51
|
+
*/
|
|
52
|
+
maybeEncrypt(value: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* Decrypt if encrypted, otherwise return as-is
|
|
55
|
+
*/
|
|
56
|
+
maybeDecrypt(value: string): string;
|
|
57
|
+
/**
|
|
58
|
+
* Generate a secure random key for API tokens, etc.
|
|
59
|
+
*/
|
|
60
|
+
static generateSecureToken(length?: number): string;
|
|
61
|
+
/**
|
|
62
|
+
* Hash a value for comparison (one-way)
|
|
63
|
+
*/
|
|
64
|
+
static hash(value: string, algorithm?: string): string;
|
|
65
|
+
/**
|
|
66
|
+
* Verify a hash
|
|
67
|
+
*/
|
|
68
|
+
static verifyHash(value: string, hash: string, algorithm?: string): boolean;
|
|
69
|
+
}
|
|
70
|
+
export declare function getCrypto(): WyrmCrypto;
|
|
71
|
+
export declare function initializeCrypto(password: string): WyrmCrypto;
|
|
72
|
+
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,MAAM,CAAe;gBAEjB,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC;IAQ1C;;OAEG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAWlC;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,OAAO,CAAC,SAAS;IAOjB;;OAEG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa;IAwBzC;;OAEG;IACH,OAAO,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM;IAmBzC;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAQnC;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAgBnC;;OAEG;IACH,MAAM,CAAC,mBAAmB,CAAC,MAAM,SAAK,GAAG,MAAM;IAI/C;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,SAAW,GAAG,MAAM;IAIxD;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,SAAW,GAAG,OAAO;CAU9E;AAKD,wBAAgB,SAAS,IAAI,UAAU,CAKtC;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAI7D"}
|