@muhgholy/next-drive 4.15.1 → 4.17.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/dist/{chunk-SSOIUMFQ.js → chunk-N3C7IKRK.js} +61 -58
- package/dist/chunk-N3C7IKRK.js.map +1 -0
- package/dist/{chunk-JZJKT2OS.cjs → chunk-XIUFYDVE.cjs} +62 -59
- package/dist/chunk-XIUFYDVE.cjs.map +1 -0
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/express.cjs +11 -11
- package/dist/server/express.js +2 -2
- package/dist/server/index.cjs +13 -13
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-JZJKT2OS.cjs.map +0 -1
- package/dist/chunk-SSOIUMFQ.js.map +0 -1
|
@@ -4,7 +4,7 @@ var formidable = require('formidable');
|
|
|
4
4
|
var path = require('path');
|
|
5
5
|
var fs = require('fs');
|
|
6
6
|
var os3 = require('os');
|
|
7
|
-
var
|
|
7
|
+
var crypto2 = require('crypto');
|
|
8
8
|
var mongoose = require('mongoose');
|
|
9
9
|
var sharp2 = require('sharp');
|
|
10
10
|
var zod = require('zod');
|
|
@@ -17,7 +17,7 @@ var formidable__default = /*#__PURE__*/_interopDefault(formidable);
|
|
|
17
17
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
18
18
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
19
19
|
var os3__default = /*#__PURE__*/_interopDefault(os3);
|
|
20
|
-
var
|
|
20
|
+
var crypto2__default = /*#__PURE__*/_interopDefault(crypto2);
|
|
21
21
|
var mongoose__default = /*#__PURE__*/_interopDefault(mongoose);
|
|
22
22
|
var sharp2__default = /*#__PURE__*/_interopDefault(sharp2);
|
|
23
23
|
var ffmpeg__default = /*#__PURE__*/_interopDefault(ffmpeg);
|
|
@@ -251,38 +251,49 @@ var runMigrations = async (storagePath) => {
|
|
|
251
251
|
};
|
|
252
252
|
|
|
253
253
|
// src/server/config.ts
|
|
254
|
-
var
|
|
255
|
-
var
|
|
256
|
-
|
|
254
|
+
var GLOBAL_KEY = "__nextDrive";
|
|
255
|
+
var getGlobal = () => {
|
|
256
|
+
if (!globalThis[GLOBAL_KEY]) {
|
|
257
|
+
globalThis[GLOBAL_KEY] = {
|
|
258
|
+
config: null,
|
|
259
|
+
migrationPromise: null,
|
|
260
|
+
initialized: false
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return globalThis[GLOBAL_KEY];
|
|
264
|
+
};
|
|
257
265
|
var driveConfiguration = async (config) => {
|
|
266
|
+
const g = getGlobal();
|
|
258
267
|
if (mongoose__default.default.connection.readyState !== 1) {
|
|
259
268
|
throw new Error("Database not connected. Please connect to Mongoose before initializing next-drive.");
|
|
260
269
|
}
|
|
261
|
-
if (
|
|
262
|
-
if (migrationPromise) await migrationPromise;
|
|
263
|
-
return
|
|
270
|
+
if (g.initialized && g.config) {
|
|
271
|
+
if (g.migrationPromise) await g.migrationPromise;
|
|
272
|
+
return g.config;
|
|
264
273
|
}
|
|
265
274
|
const resolvedPath = config.storage?.path || path__default.default.join(os3__default.default.tmpdir(), "next-drive-data");
|
|
266
275
|
const mode = config.mode || "NORMAL";
|
|
267
276
|
if (mode === "ROOT") {
|
|
268
|
-
|
|
277
|
+
g.config = {
|
|
269
278
|
...config,
|
|
270
279
|
mode: "ROOT",
|
|
271
280
|
storage: {
|
|
272
281
|
...config.storage,
|
|
273
282
|
path: resolvedPath
|
|
274
283
|
},
|
|
275
|
-
security:
|
|
276
|
-
maxUploadSizeInBytes: 1024 * 1024 * 1024 * 10,
|
|
284
|
+
security: {
|
|
285
|
+
maxUploadSizeInBytes: config.security?.maxUploadSizeInBytes ?? 1024 * 1024 * 1024 * 10,
|
|
277
286
|
// 10GB default for ROOT
|
|
278
|
-
allowedMimeTypes: ["*/*"]
|
|
287
|
+
allowedMimeTypes: config.security?.allowedMimeTypes ?? ["*/*"],
|
|
288
|
+
signedUrls: config.security?.signedUrls,
|
|
289
|
+
trash: config.security?.trash
|
|
279
290
|
}
|
|
280
291
|
};
|
|
281
292
|
} else {
|
|
282
293
|
if (!config.information) {
|
|
283
294
|
throw new Error("information callback is required in NORMAL mode");
|
|
284
295
|
}
|
|
285
|
-
|
|
296
|
+
g.config = {
|
|
286
297
|
...config,
|
|
287
298
|
mode: "NORMAL",
|
|
288
299
|
storage: {
|
|
@@ -298,16 +309,17 @@ var driveConfiguration = async (config) => {
|
|
|
298
309
|
information: config.information
|
|
299
310
|
};
|
|
300
311
|
}
|
|
301
|
-
|
|
302
|
-
if (!migrationPromise) {
|
|
303
|
-
migrationPromise = runMigrations(resolvedPath);
|
|
312
|
+
g.initialized = true;
|
|
313
|
+
if (!g.migrationPromise) {
|
|
314
|
+
g.migrationPromise = runMigrations(resolvedPath);
|
|
304
315
|
}
|
|
305
|
-
await migrationPromise;
|
|
306
|
-
return
|
|
316
|
+
await g.migrationPromise;
|
|
317
|
+
return g.config;
|
|
307
318
|
};
|
|
308
319
|
var getDriveConfig = () => {
|
|
309
|
-
|
|
310
|
-
|
|
320
|
+
const g = getGlobal();
|
|
321
|
+
if (!g.config) throw new Error("Drive configuration not initialized");
|
|
322
|
+
return g.config;
|
|
311
323
|
};
|
|
312
324
|
var getDriveInformation = async (req) => {
|
|
313
325
|
const config = getDriveConfig();
|
|
@@ -364,7 +376,7 @@ var validateMimeType = (mime, allowedTypes) => {
|
|
|
364
376
|
});
|
|
365
377
|
};
|
|
366
378
|
var computeFileHash = (filePath) => new Promise((resolve, reject) => {
|
|
367
|
-
const hash =
|
|
379
|
+
const hash = crypto2__default.default.createHash("sha256");
|
|
368
380
|
const stream = fs__default.default.createReadStream(filePath);
|
|
369
381
|
stream.on("data", (data) => hash.update(data));
|
|
370
382
|
stream.on("end", () => resolve(hash.digest("hex")));
|
|
@@ -1286,7 +1298,7 @@ var driveGetUrl = (fileId, options) => {
|
|
|
1286
1298
|
} else {
|
|
1287
1299
|
expiryTimestamp = Math.floor(Date.now() / 1e3) + expiresIn;
|
|
1288
1300
|
}
|
|
1289
|
-
const signature =
|
|
1301
|
+
const signature = crypto2__default.default.createHmac("sha256", secret).update(`${fileId}:${expiryTimestamp}`).digest("hex");
|
|
1290
1302
|
const token = Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url");
|
|
1291
1303
|
return `/api/drive?action=serve&id=${fileId}&token=${token}`;
|
|
1292
1304
|
};
|
|
@@ -1552,7 +1564,7 @@ var driveUpload = async (source, key, options) => {
|
|
|
1552
1564
|
if (!fs__default.default.existsSync(tempDir)) {
|
|
1553
1565
|
fs__default.default.mkdirSync(tempDir, { recursive: true });
|
|
1554
1566
|
}
|
|
1555
|
-
tempFilePath = path__default.default.join(tempDir, `upload-${
|
|
1567
|
+
tempFilePath = path__default.default.join(tempDir, `upload-${crypto2__default.default.randomUUID()}.tmp`);
|
|
1556
1568
|
fs__default.default.writeFileSync(tempFilePath, source);
|
|
1557
1569
|
sourceFilePath = tempFilePath;
|
|
1558
1570
|
fileSize = source.length;
|
|
@@ -1561,7 +1573,7 @@ var driveUpload = async (source, key, options) => {
|
|
|
1561
1573
|
if (!fs__default.default.existsSync(tempDir)) {
|
|
1562
1574
|
fs__default.default.mkdirSync(tempDir, { recursive: true });
|
|
1563
1575
|
}
|
|
1564
|
-
tempFilePath = path__default.default.join(tempDir, `upload-${
|
|
1576
|
+
tempFilePath = path__default.default.join(tempDir, `upload-${crypto2__default.default.randomUUID()}.tmp`);
|
|
1565
1577
|
const writeStream = fs__default.default.createWriteStream(tempFilePath);
|
|
1566
1578
|
await new Promise((resolve, reject) => {
|
|
1567
1579
|
source.pipe(writeStream);
|
|
@@ -1669,6 +1681,21 @@ var getProvider = async (req, owner) => {
|
|
|
1669
1681
|
if (account.metadata.provider === "GOOGLE") return { provider: GoogleDriveProvider, accountId: account._id.toString() };
|
|
1670
1682
|
return { provider: LocalStorageProvider };
|
|
1671
1683
|
};
|
|
1684
|
+
var addSignedUrlToken = (item, config) => {
|
|
1685
|
+
if (!config.security?.signedUrls?.enabled || !config.security.signedUrls.secret) {
|
|
1686
|
+
return item;
|
|
1687
|
+
}
|
|
1688
|
+
const { secret, expiresIn } = config.security.signedUrls;
|
|
1689
|
+
const expiryTimestamp = Math.floor(Date.now() / 1e3) + expiresIn;
|
|
1690
|
+
const signature = crypto2__default.default.createHmac("sha256", secret).update(`${item.id}:${expiryTimestamp}`).digest("hex");
|
|
1691
|
+
return { ...item, token: Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url") };
|
|
1692
|
+
};
|
|
1693
|
+
var addSignedUrlTokens = (items, config) => {
|
|
1694
|
+
if (!config.security?.signedUrls?.enabled || !config.security.signedUrls.secret) {
|
|
1695
|
+
return items;
|
|
1696
|
+
}
|
|
1697
|
+
return items.map((item) => addSignedUrlToken(item, config));
|
|
1698
|
+
};
|
|
1672
1699
|
var applyCorsHeaders = (req, res, config) => {
|
|
1673
1700
|
const cors = config.cors;
|
|
1674
1701
|
if (!cors?.enabled) return false;
|
|
@@ -1750,7 +1777,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
1750
1777
|
return res.status(401).json({ status: 401, message: "Token expired" });
|
|
1751
1778
|
}
|
|
1752
1779
|
const { secret } = config.security.signedUrls;
|
|
1753
|
-
const expectedSignature =
|
|
1780
|
+
const expectedSignature = crypto2__default.default.createHmac("sha256", secret).update(`${id}:${expiry}`).digest("hex");
|
|
1754
1781
|
if (signature !== expectedSignature) {
|
|
1755
1782
|
return res.status(401).json({ status: 401, message: "Invalid token" });
|
|
1756
1783
|
}
|
|
@@ -2024,15 +2051,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2024
2051
|
}
|
|
2025
2052
|
if (afterId) query._id = { $lt: afterId };
|
|
2026
2053
|
const items = await drive_default.find(query, {}, { sort: { order: 1, _id: -1 }, limit });
|
|
2027
|
-
|
|
2028
|
-
if (config.security?.signedUrls?.enabled && config.security.signedUrls.secret) {
|
|
2029
|
-
const { secret, expiresIn } = config.security.signedUrls;
|
|
2030
|
-
plainItems = plainItems.map((item) => {
|
|
2031
|
-
const expiryTimestamp = Math.floor(Date.now() / 1e3) + expiresIn;
|
|
2032
|
-
const signature = crypto3__default.default.createHmac("sha256", secret).update(`${item.id}:${expiryTimestamp}`).digest("hex");
|
|
2033
|
-
return { ...item, token: Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url") };
|
|
2034
|
-
});
|
|
2035
|
-
}
|
|
2054
|
+
const plainItems = addSignedUrlTokens(await Promise.all(items.map((item) => item.toClient())), config);
|
|
2036
2055
|
res.status(200).json({ status: 200, message: "Items retrieved", data: { items: plainItems, hasMore: items.length === limit } });
|
|
2037
2056
|
return;
|
|
2038
2057
|
}
|
|
@@ -2059,15 +2078,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2059
2078
|
}
|
|
2060
2079
|
if (folderId && folderId !== "root") query.parentId = folderId;
|
|
2061
2080
|
const items = await drive_default.find(query, {}, { limit, sort: { createdAt: -1 } });
|
|
2062
|
-
|
|
2063
|
-
if (config.security?.signedUrls?.enabled && config.security.signedUrls.secret) {
|
|
2064
|
-
const { secret, expiresIn } = config.security.signedUrls;
|
|
2065
|
-
plainItems = plainItems.map((item) => {
|
|
2066
|
-
const expiryTimestamp = Math.floor(Date.now() / 1e3) + expiresIn;
|
|
2067
|
-
const signature = crypto3__default.default.createHmac("sha256", secret).update(`${item.id}:${expiryTimestamp}`).digest("hex");
|
|
2068
|
-
return { ...item, token: Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url") };
|
|
2069
|
-
});
|
|
2070
|
-
}
|
|
2081
|
+
const plainItems = addSignedUrlTokens(await Promise.all(items.map((i) => i.toClient())), config);
|
|
2071
2082
|
return res.status(200).json({ status: 200, message: "Results", data: { items: plainItems } });
|
|
2072
2083
|
}
|
|
2073
2084
|
// ** 3. UPLOAD **
|
|
@@ -2125,7 +2136,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2125
2136
|
return res.status(413).json({ status: 413, message: "Storage quota exceeded" });
|
|
2126
2137
|
}
|
|
2127
2138
|
}
|
|
2128
|
-
currentUploadId =
|
|
2139
|
+
currentUploadId = crypto2__default.default.randomUUID();
|
|
2129
2140
|
const uploadDir = path__default.default.join(tempBaseDir, currentUploadId);
|
|
2130
2141
|
fs__default.default.mkdirSync(uploadDir, { recursive: true });
|
|
2131
2142
|
const metadata = {
|
|
@@ -2230,7 +2241,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2230
2241
|
const item = await provider.uploadFile(drive, finalTempPath, meta.accountId);
|
|
2231
2242
|
fs__default.default.rmSync(uploadDir, { recursive: true, force: true });
|
|
2232
2243
|
const newQuota = await provider.getQuota(meta.owner, meta.accountId, information.storage.quotaInBytes);
|
|
2233
|
-
res.status(200).json({ status: 200, message: "Upload complete", data: { type: "UPLOAD_COMPLETE", driveId: String(drive._id), item }, statistic: { storage: newQuota } });
|
|
2244
|
+
res.status(200).json({ status: 200, message: "Upload complete", data: { type: "UPLOAD_COMPLETE", driveId: String(drive._id), item: addSignedUrlToken(item, config) }, statistic: { storage: newQuota } });
|
|
2234
2245
|
} catch (err) {
|
|
2235
2246
|
await drive_default.deleteOne({ _id: drive._id });
|
|
2236
2247
|
throw err;
|
|
@@ -2272,7 +2283,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2272
2283
|
const folderData = createFolderBodySchema.safeParse(req.body);
|
|
2273
2284
|
if (!folderData.success) return res.status(400).json({ status: 400, message: folderData.error.errors[0].message });
|
|
2274
2285
|
const { name, parentId } = folderData.data;
|
|
2275
|
-
const item = await provider.createFolder(name, parentId ?? null, owner, accountId);
|
|
2286
|
+
const item = addSignedUrlToken(await provider.createFolder(name, parentId ?? null, owner, accountId), config);
|
|
2276
2287
|
return res.status(201).json({ status: 201, message: "Folder created", data: { item } });
|
|
2277
2288
|
}
|
|
2278
2289
|
// ** 5. DELETE **
|
|
@@ -2327,15 +2338,7 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2327
2338
|
trashedAt: { $ne: null }
|
|
2328
2339
|
};
|
|
2329
2340
|
const items = await drive_default.find(query, {}, { sort: { trashedAt: -1 } });
|
|
2330
|
-
|
|
2331
|
-
if (config.security?.signedUrls?.enabled && config.security.signedUrls.secret) {
|
|
2332
|
-
const { secret, expiresIn } = config.security.signedUrls;
|
|
2333
|
-
plainItems = plainItems.map((item) => {
|
|
2334
|
-
const expiryTimestamp = Math.floor(Date.now() / 1e3) + expiresIn;
|
|
2335
|
-
const signature = crypto3__default.default.createHmac("sha256", secret).update(`${item.id}:${expiryTimestamp}`).digest("hex");
|
|
2336
|
-
return { ...item, token: Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url") };
|
|
2337
|
-
});
|
|
2338
|
-
}
|
|
2341
|
+
const plainItems = addSignedUrlTokens(await Promise.all(items.map((item) => item.toClient())), config);
|
|
2339
2342
|
return res.status(200).json({
|
|
2340
2343
|
status: 200,
|
|
2341
2344
|
message: "Trash items",
|
|
@@ -2390,14 +2393,14 @@ var driveAPIHandler = async (req, res) => {
|
|
|
2390
2393
|
console.error(`Failed to move item ${id}`, e);
|
|
2391
2394
|
}
|
|
2392
2395
|
}
|
|
2393
|
-
return res.status(200).json({ status: 200, message: "Moved", data: { items } });
|
|
2396
|
+
return res.status(200).json({ status: 200, message: "Moved", data: { items: addSignedUrlTokens(items, config) } });
|
|
2394
2397
|
}
|
|
2395
2398
|
// ** 8. RENAME **
|
|
2396
2399
|
case "rename": {
|
|
2397
2400
|
const renameData = renameBodySchema.safeParse({ id: req.query.id, ...req.body });
|
|
2398
2401
|
if (!renameData.success) return res.status(400).json({ status: 400, message: "Invalid data" });
|
|
2399
2402
|
const { id, newName } = renameData.data;
|
|
2400
|
-
const item = await provider.rename(id, newName, owner, accountId);
|
|
2403
|
+
const item = addSignedUrlToken(await provider.rename(id, newName, owner, accountId), config);
|
|
2401
2404
|
return res.status(200).json({ status: 200, message: "Renamed", data: { item } });
|
|
2402
2405
|
}
|
|
2403
2406
|
// ** 9. THUMBNAIL **
|
|
@@ -2422,5 +2425,5 @@ exports.driveReadFile = driveReadFile;
|
|
|
2422
2425
|
exports.driveUpload = driveUpload;
|
|
2423
2426
|
exports.getDriveConfig = getDriveConfig;
|
|
2424
2427
|
exports.getDriveInformation = getDriveInformation;
|
|
2425
|
-
//# sourceMappingURL=chunk-
|
|
2426
|
-
//# sourceMappingURL=chunk-
|
|
2428
|
+
//# sourceMappingURL=chunk-XIUFYDVE.cjs.map
|
|
2429
|
+
//# sourceMappingURL=chunk-XIUFYDVE.cjs.map
|