@muhgholy/next-drive 4.23.3 → 4.23.5

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.
@@ -5,9 +5,9 @@ import os2 from 'os';
5
5
  import crypto2 from 'crypto';
6
6
  import mongoose, { Schema, isValidObjectId } from 'mongoose';
7
7
  import sharp2 from 'sharp';
8
- import { z } from 'zod';
9
8
  import ffmpeg from 'fluent-ffmpeg';
10
9
  import { google } from 'googleapis';
10
+ import { z } from 'zod';
11
11
 
12
12
  // src/server/index.ts
13
13
  var informationSchema = new Schema({
@@ -324,35 +324,6 @@ var getDriveInformation = async (input) => {
324
324
  }
325
325
  return config.information(input);
326
326
  };
327
- var StorageAccountSchema = new Schema(
328
- {
329
- owner: { type: Schema.Types.Mixed, default: null },
330
- name: { type: String, required: true },
331
- metadata: {
332
- provider: { type: String, enum: ["GOOGLE"], required: true },
333
- google: {
334
- email: { type: String, required: true },
335
- credentials: { type: Schema.Types.Mixed, required: true }
336
- }
337
- },
338
- createdAt: { type: Date, default: Date.now }
339
- },
340
- { minimize: false }
341
- );
342
- StorageAccountSchema.index({ owner: 1, "metadata.provider": 1 });
343
- StorageAccountSchema.index({ owner: 1, "metadata.google.email": 1 });
344
- StorageAccountSchema.method("toClient", async function() {
345
- const data = this.toJSON();
346
- return {
347
- id: String(data._id),
348
- owner: data.owner,
349
- name: data.name,
350
- metadata: data.metadata,
351
- createdAt: data.createdAt
352
- };
353
- });
354
- var StorageAccount = mongoose.models.StorageAccount || mongoose.model("StorageAccount", StorageAccountSchema);
355
- var account_default = StorageAccount;
356
327
  var validateMimeType = (mime, allowedTypes) => {
357
328
  if (allowedTypes.includes("*/*")) return true;
358
329
  return allowedTypes.some((pattern) => {
@@ -516,97 +487,6 @@ var getImageSettings = (fileSizeInBytes, qualityPreset, display, size, fit, posi
516
487
  ...resolvedPosition && { position: resolvedPosition }
517
488
  };
518
489
  };
519
- var objectIdSchema = z.string().refine((val) => isValidObjectId(val), {
520
- message: "Invalid ObjectId format"
521
- });
522
- var sanitizeFilename = (name) => {
523
- return name.replace(/[<>:"|?*\x00-\x1F]/g, "").replace(/^\.+/, "").replace(/\.+$/, "").replace(/\\/g, "/").replace(/\/+/g, "/").replace(/\.\.\//g, "").replace(/\.\.+/g, "").split("/").pop() || "".trim().slice(0, 255);
524
- };
525
- var sanitizeRegexInput = (input) => {
526
- return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").slice(0, 100);
527
- };
528
- var nameSchema = z.string().min(1, "Name is required").max(255, "Name too long").transform(sanitizeFilename).refine((val) => val.length > 0, { message: "Invalid name after sanitization" });
529
- var uploadChunkSchema = z.object({
530
- chunkIndex: z.number().int().min(0).max(1e4),
531
- totalChunks: z.number().int().min(1).max(1e4),
532
- driveId: z.string().optional(),
533
- fileName: nameSchema,
534
- fileSize: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
535
- fileType: z.string().min(1).max(255),
536
- folderId: z.string().optional()
537
- }).refine((data) => data.chunkIndex < data.totalChunks, {
538
- message: "Chunk index must be less than total chunks"
539
- });
540
- var listQuerySchema = z.object({
541
- folderId: z.union([z.literal("root"), objectIdSchema, z.undefined()]),
542
- limit: z.string().optional().transform((val) => {
543
- const num = parseInt(val || "50", 10);
544
- return Math.min(Math.max(1, num), 100);
545
- }),
546
- afterId: objectIdSchema.optional()
547
- });
548
- z.object({
549
- id: objectIdSchema,
550
- token: z.string().optional()
551
- });
552
- z.object({
553
- id: objectIdSchema,
554
- size: z.enum(["small", "medium", "large"]).optional().default("medium"),
555
- token: z.string().optional()
556
- });
557
- var renameBodySchema = z.object({
558
- id: objectIdSchema,
559
- newName: nameSchema
560
- });
561
- var deleteQuerySchema = z.object({
562
- id: objectIdSchema
563
- });
564
- z.object({
565
- ids: z.array(objectIdSchema).min(1).max(1e3)
566
- });
567
- var createFolderBodySchema = z.object({
568
- name: nameSchema,
569
- parentId: z.union([z.literal("root"), objectIdSchema, z.string().length(0), z.undefined()]).optional()
570
- });
571
- var moveBodySchema = z.object({
572
- ids: z.array(objectIdSchema).min(1).max(1e3),
573
- targetFolderId: z.union([z.literal("root"), objectIdSchema, z.undefined()]).optional()
574
- });
575
- z.object({
576
- ids: z.array(objectIdSchema).min(1).max(1e3)
577
- });
578
- var searchQuerySchema = z.object({
579
- q: z.string().min(1).max(100).transform(sanitizeRegexInput),
580
- folderId: z.union([z.literal("root"), objectIdSchema, z.undefined()]).optional(),
581
- limit: z.string().optional().transform((val) => {
582
- const num = parseInt(val || "50", 10);
583
- return Math.min(Math.max(1, num), 100);
584
- }),
585
- trashed: z.string().optional().transform((val) => val === "true")
586
- });
587
- z.object({
588
- id: objectIdSchema
589
- });
590
- var cancelQuerySchema = z.object({
591
- id: z.string().uuid()
592
- });
593
- z.object({
594
- days: z.number().int().min(1).max(365).optional()
595
- });
596
- var driveFileSchemaZod = z.object({
597
- id: z.string(),
598
- file: z.object({
599
- name: z.string(),
600
- mime: z.string(),
601
- size: z.number()
602
- })
603
- });
604
-
605
- // src/server/security/cryptoUtils.ts
606
- function sanitizeContentDispositionFilename(filename) {
607
- const basename = filename.replace(/^.*[\\\/]/, "");
608
- return basename.replace(/["\r\n]/g, "").replace(/[^\x20-\x7E]/g, "").slice(0, 255);
609
- }
610
490
  var generatePlaceholderThumbnail = async (outputPath, mimeType) => {
611
491
  const typeParts = mimeType.split("/");
612
492
  const subtype = typeParts[1] || "file";
@@ -803,6 +683,37 @@ var LocalStorageProvider = {
803
683
  revokeToken: async (owner, accountId) => {
804
684
  }
805
685
  };
686
+ var StorageAccountSchema = new Schema(
687
+ {
688
+ owner: { type: Schema.Types.Mixed, default: null },
689
+ name: { type: String, required: true },
690
+ metadata: {
691
+ provider: { type: String, enum: ["GOOGLE"], required: true },
692
+ google: {
693
+ email: { type: String, required: true },
694
+ credentials: { type: Schema.Types.Mixed, required: true }
695
+ }
696
+ },
697
+ createdAt: { type: Date, default: Date.now }
698
+ },
699
+ { minimize: false }
700
+ );
701
+ StorageAccountSchema.index({ owner: 1, "metadata.provider": 1 });
702
+ StorageAccountSchema.index({ owner: 1, "metadata.google.email": 1 });
703
+ StorageAccountSchema.method("toClient", async function() {
704
+ const data = this.toJSON();
705
+ return {
706
+ id: String(data._id),
707
+ owner: data.owner,
708
+ name: data.name,
709
+ metadata: data.metadata,
710
+ createdAt: data.createdAt
711
+ };
712
+ });
713
+ var StorageAccount = mongoose.models.StorageAccount || mongoose.model("StorageAccount", StorageAccountSchema);
714
+ var account_default = StorageAccount;
715
+
716
+ // src/server/providers/google.ts
806
717
  var createAuthClient = async (owner, accountId) => {
807
718
  const query = { owner, "metadata.provider": "GOOGLE" };
808
719
  if (accountId) query._id = accountId;
@@ -1269,6 +1180,8 @@ var GoogleDriveProvider = {
1269
1180
  }
1270
1181
  }
1271
1182
  };
1183
+
1184
+ // src/server/controllers/drive.ts
1272
1185
  var getNextOrderValue = async (owner) => {
1273
1186
  const lastItem = await drive_default.findOne({ owner }, {}, { sort: { order: -1 } });
1274
1187
  return lastItem ? lastItem.order + 1 : 0;
@@ -1289,7 +1202,22 @@ var driveGetUrl = (fileId, options) => {
1289
1202
  }
1290
1203
  const signature = crypto2.createHmac("sha256", secret).update(`${fileId}:${expiryTimestamp}`).digest("hex");
1291
1204
  const token = Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url");
1292
- return `/api/drive?action=serve&id=${fileId}&token=${token}`;
1205
+ return `${config.apiUrl || "/api/drive"}?action=serve&id=${fileId}&token=${token}`;
1206
+ };
1207
+ var driveAddSignedUrlToken = (item, config) => {
1208
+ let token;
1209
+ if (config.security?.signedUrls?.enabled && config.security.signedUrls.secret) {
1210
+ const { secret, expiresIn } = config.security.signedUrls;
1211
+ const expiryTimestamp = Math.floor(Date.now() / 1e3) + expiresIn;
1212
+ const signature = crypto2.createHmac("sha256", secret).update(`${item.id}:${expiryTimestamp}`).digest("hex");
1213
+ token = Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url");
1214
+ }
1215
+ const apiUrl = config.apiUrl || "/api/drive";
1216
+ const url = `${apiUrl}?action=serve&id=${item.id}${token ? `&token=${token}` : ""}`;
1217
+ return { ...item, token, url };
1218
+ };
1219
+ var driveAddSignedUrlTokens = (items, config) => {
1220
+ return items.map((item) => driveAddSignedUrlToken(item, config));
1293
1221
  };
1294
1222
  var driveReadFile = async (file) => {
1295
1223
  let drive;
@@ -1449,7 +1377,8 @@ var driveList = async (options) => {
1449
1377
  query._id = { $lt: afterId };
1450
1378
  }
1451
1379
  const items = await drive_default.find(query, {}, { sort: { order: 1, _id: -1 }, limit });
1452
- return await Promise.all(items.map((item) => item.toClient()));
1380
+ const config = getDriveConfig();
1381
+ return driveAddSignedUrlTokens(await Promise.all(items.map((item) => item.toClient())), config);
1453
1382
  };
1454
1383
  var driveListFiles = async (options) => {
1455
1384
  const { key, folderId, accountId } = options;
@@ -1485,8 +1414,9 @@ var driveListFiles = async (options) => {
1485
1414
  drive_default.find(query, {}, { sort: { createdAt: -1 }, skip, limit })
1486
1415
  ]);
1487
1416
  const totalPages = Math.ceil(totalCount / limit);
1417
+ const config = getDriveConfig();
1488
1418
  return {
1489
- items: await Promise.all(items.map((item) => item.toClient())),
1419
+ items: driveAddSignedUrlTokens(await Promise.all(items.map((item) => item.toClient())), config),
1490
1420
  pagination: {
1491
1421
  page,
1492
1422
  limit,
@@ -1778,8 +1708,97 @@ var driveCleanup = async () => {
1778
1708
  }
1779
1709
  return { removed, totalFreedInBytes };
1780
1710
  };
1711
+ var objectIdSchema = z.string().refine((val) => isValidObjectId(val), {
1712
+ message: "Invalid ObjectId format"
1713
+ });
1714
+ var sanitizeFilename = (name) => {
1715
+ return name.replace(/[<>:"|?*\x00-\x1F]/g, "").replace(/^\.+/, "").replace(/\.+$/, "").replace(/\\/g, "/").replace(/\/+/g, "/").replace(/\.\.\//g, "").replace(/\.\.+/g, "").split("/").pop() || "".trim().slice(0, 255);
1716
+ };
1717
+ var sanitizeRegexInput = (input) => {
1718
+ return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").slice(0, 100);
1719
+ };
1720
+ var nameSchema = z.string().min(1, "Name is required").max(255, "Name too long").transform(sanitizeFilename).refine((val) => val.length > 0, { message: "Invalid name after sanitization" });
1721
+ var uploadChunkSchema = z.object({
1722
+ chunkIndex: z.number().int().min(0).max(1e4),
1723
+ totalChunks: z.number().int().min(1).max(1e4),
1724
+ driveId: z.string().optional(),
1725
+ fileName: nameSchema,
1726
+ fileSize: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
1727
+ fileType: z.string().min(1).max(255),
1728
+ folderId: z.string().optional()
1729
+ }).refine((data) => data.chunkIndex < data.totalChunks, {
1730
+ message: "Chunk index must be less than total chunks"
1731
+ });
1732
+ var listQuerySchema = z.object({
1733
+ folderId: z.union([z.literal("root"), objectIdSchema, z.undefined()]),
1734
+ limit: z.string().optional().transform((val) => {
1735
+ const num = parseInt(val || "50", 10);
1736
+ return Math.min(Math.max(1, num), 100);
1737
+ }),
1738
+ afterId: objectIdSchema.optional()
1739
+ });
1740
+ z.object({
1741
+ id: objectIdSchema,
1742
+ token: z.string().optional()
1743
+ });
1744
+ z.object({
1745
+ id: objectIdSchema,
1746
+ size: z.enum(["small", "medium", "large"]).optional().default("medium"),
1747
+ token: z.string().optional()
1748
+ });
1749
+ var renameBodySchema = z.object({
1750
+ id: objectIdSchema,
1751
+ newName: nameSchema
1752
+ });
1753
+ var deleteQuerySchema = z.object({
1754
+ id: objectIdSchema
1755
+ });
1756
+ z.object({
1757
+ ids: z.array(objectIdSchema).min(1).max(1e3)
1758
+ });
1759
+ var createFolderBodySchema = z.object({
1760
+ name: nameSchema,
1761
+ parentId: z.union([z.literal("root"), objectIdSchema, z.string().length(0), z.undefined()]).optional()
1762
+ });
1763
+ var moveBodySchema = z.object({
1764
+ ids: z.array(objectIdSchema).min(1).max(1e3),
1765
+ targetFolderId: z.union([z.literal("root"), objectIdSchema, z.undefined()]).optional()
1766
+ });
1767
+ z.object({
1768
+ ids: z.array(objectIdSchema).min(1).max(1e3)
1769
+ });
1770
+ var searchQuerySchema = z.object({
1771
+ q: z.string().min(1).max(100).transform(sanitizeRegexInput),
1772
+ folderId: z.union([z.literal("root"), objectIdSchema, z.undefined()]).optional(),
1773
+ limit: z.string().optional().transform((val) => {
1774
+ const num = parseInt(val || "50", 10);
1775
+ return Math.min(Math.max(1, num), 100);
1776
+ }),
1777
+ trashed: z.string().optional().transform((val) => val === "true")
1778
+ });
1779
+ z.object({
1780
+ id: objectIdSchema
1781
+ });
1782
+ var cancelQuerySchema = z.object({
1783
+ id: z.string().uuid()
1784
+ });
1785
+ z.object({
1786
+ days: z.number().int().min(1).max(365).optional()
1787
+ });
1788
+ var driveFileSchemaZod = z.object({
1789
+ id: z.string(),
1790
+ file: z.object({
1791
+ name: z.string(),
1792
+ mime: z.string(),
1793
+ size: z.number()
1794
+ })
1795
+ });
1781
1796
 
1782
- // src/server/index.ts
1797
+ // src/server/security/cryptoUtils.ts
1798
+ function sanitizeContentDispositionFilename(filename) {
1799
+ const basename = filename.replace(/^.*[\\\/]/, "");
1800
+ return basename.replace(/["\r\n]/g, "").replace(/[^\x20-\x7E]/g, "").slice(0, 255);
1801
+ }
1783
1802
  var getProvider = async (req, owner) => {
1784
1803
  const accountId = req.headers["x-drive-account"];
1785
1804
  if (!accountId || accountId === "LOCAL") {
@@ -1793,19 +1812,10 @@ var getProvider = async (req, owner) => {
1793
1812
  return { provider: LocalStorageProvider };
1794
1813
  };
1795
1814
  var addSignedUrlToken = (item, config) => {
1796
- if (!config.security?.signedUrls?.enabled || !config.security.signedUrls.secret) {
1797
- return item;
1798
- }
1799
- const { secret, expiresIn } = config.security.signedUrls;
1800
- const expiryTimestamp = Math.floor(Date.now() / 1e3) + expiresIn;
1801
- const signature = crypto2.createHmac("sha256", secret).update(`${item.id}:${expiryTimestamp}`).digest("hex");
1802
- return { ...item, token: Buffer.from(`${expiryTimestamp}:${signature}`).toString("base64url") };
1815
+ return driveAddSignedUrlToken(item, config);
1803
1816
  };
1804
1817
  var addSignedUrlTokens = (items, config) => {
1805
- if (!config.security?.signedUrls?.enabled || !config.security.signedUrls.secret) {
1806
- return items;
1807
- }
1808
- return items.map((item) => addSignedUrlToken(item, config));
1818
+ return driveAddSignedUrlTokens(items, config);
1809
1819
  };
1810
1820
  var applyCorsHeaders = (req, res, config) => {
1811
1821
  const cors = config.cors;
@@ -2525,5 +2535,5 @@ var driveAPIHandler = async (req, res) => {
2525
2535
  };
2526
2536
 
2527
2537
  export { driveAPIHandler, driveCleanup, driveConfiguration, driveDelete, driveFilePath, driveFileSchemaZod, driveGetUrl, driveInfo, driveList, driveListFiles, driveReadFile, driveUpload, drive_default, getDriveConfig, getDriveInformation };
2528
- //# sourceMappingURL=chunk-R43JCXQB.js.map
2529
- //# sourceMappingURL=chunk-R43JCXQB.js.map
2538
+ //# sourceMappingURL=chunk-GV4HB2G6.js.map
2539
+ //# sourceMappingURL=chunk-GV4HB2G6.js.map