From 412440a77bbef260347d5603ec08ff50837cc199 Mon Sep 17 00:00:00 2001 From: subnub Date: Thu, 16 Apr 2020 04:26:44 -0400 Subject: [PATCH] Started adding the ability to store file chunks in the file system :) --- backend/controllers/FileSystem/fileSystem.ts | 0 backend/controllers/file.ts | 7 +- backend/controllers/{folder.js => folder.ts} | 23 +- backend/models/file.ts | 76 ++++++- backend/models/fileSystem.ts | 69 ++++++ .../ChunkService/FileSystemService.ts | 113 ++++++++++ backend/services/ChunkService/MongoService.ts | 5 +- .../ChunkService/utils/ChunkInterface.ts | 14 ++ .../ChunkService/utils/getFileSize.ts | 19 ++ dist/controllers/FileSystem/fileSystem.js | 1 + dist/controllers/file.js | 6 +- dist/controllers/folder.js | 1 + dist/models/file.js | 61 ++++++ dist/models/fileSystem.js | 55 +++++ .../ChunkService/FileSystemService.js | 90 ++++++++ dist/services/ChunkService/MongoService.js | 203 ------------------ .../ChunkService/utils/ChunkInterface.js | 2 + .../ChunkService/utils/getFileSize.js | 17 ++ package.json | 1 + 19 files changed, 541 insertions(+), 222 deletions(-) create mode 100644 backend/controllers/FileSystem/fileSystem.ts rename backend/controllers/{folder.js => folder.ts} (84%) create mode 100644 backend/models/fileSystem.ts create mode 100644 backend/services/ChunkService/FileSystemService.ts create mode 100644 backend/services/ChunkService/utils/ChunkInterface.ts create mode 100644 backend/services/ChunkService/utils/getFileSize.ts create mode 100644 dist/controllers/FileSystem/fileSystem.js create mode 100644 dist/models/fileSystem.js create mode 100644 dist/services/ChunkService/FileSystemService.js create mode 100644 dist/services/ChunkService/utils/ChunkInterface.js create mode 100644 dist/services/ChunkService/utils/getFileSize.js diff --git a/backend/controllers/FileSystem/fileSystem.ts b/backend/controllers/FileSystem/fileSystem.ts new file mode 100644 index 0000000..e69de29 diff --git a/backend/controllers/file.ts b/backend/controllers/file.ts index a7b48d8..d28fa91 100644 --- a/backend/controllers/file.ts +++ b/backend/controllers/file.ts @@ -9,6 +9,9 @@ const fileService = new FileService() import MongoService from "../services/ChunkService/MongoService"; const mongoService = new MongoService(); +import FileSystemService from "../services/ChunkService/FileSystemService"; +const fileSystemService = new FileSystemService(); + import {UserInterface} from "../models/user"; interface RequestType extends Request { @@ -87,7 +90,7 @@ class FileController { req.pipe(busboy); - const file = await mongoService.uploadFile(user, busboy, req); + const file = await fileSystemService.uploadFile(user, busboy, req); res.send(file); @@ -473,7 +476,7 @@ class FileController { const fileID = req.params.id; //await fileService.downloadFile(user, fileID, res); - await mongoService.downloadFile(user, fileID, res); + await fileSystemService.downloadFile(user, fileID, res); } catch (e) { diff --git a/backend/controllers/folder.js b/backend/controllers/folder.ts similarity index 84% rename from backend/controllers/folder.js rename to backend/controllers/folder.ts index 8ee3529..0505aa7 100644 --- a/backend/controllers/folder.js +++ b/backend/controllers/folder.ts @@ -1,5 +1,12 @@ const FolderService = require("../services/FolderService"); const folderService = new FolderService(); +import { Request, Response } from "express"; +import {UserInterface} from "../models/user"; + +interface RequestType extends Request { + user?: UserInterface, + auth?: any, +} class FolderController { @@ -7,7 +14,7 @@ class FolderController { } - async uploadFolder(req, res) { + async uploadFolder(req: RequestType, res: Response) { if (!req.user) { @@ -31,7 +38,7 @@ class FolderController { } } - async deleteFolder(req, res) { + async deleteFolder(req: RequestType, res: Response) { if (!req.user) { @@ -57,7 +64,7 @@ class FolderController { } } - async deleteAll(req, res) { + async deleteAll(req: RequestType, res: Response) { if (!req.user) { @@ -81,7 +88,7 @@ class FolderController { } } - async getInfo(req, res) { + async getInfo(req: RequestType, res: Response) { if (!req.user) { return; @@ -105,7 +112,7 @@ class FolderController { } } - async getSubfolderList(req, res) { + async getSubfolderList(req: RequestType, res: Response) { if (!req.user) { @@ -130,7 +137,7 @@ class FolderController { } } - async getFolderList(req, res) { + async getFolderList(req: RequestType, res: Response) { if (!req.user) { @@ -155,7 +162,7 @@ class FolderController { } } - async moveFolder(req, res) { + async moveFolder(req: RequestType, res: Response) { if (!req.user) { return; @@ -181,7 +188,7 @@ class FolderController { } } - async renameFolder(req, res) { + async renameFolder(req: RequestType, res: Response) { if (!req.user) { return; diff --git a/backend/models/file.ts b/backend/models/file.ts index a03af91..44c18df 100644 --- a/backend/models/file.ts +++ b/backend/models/file.ts @@ -1,8 +1,68 @@ -export interface FileInterface { - _id: string, +import mongoose, {Document} from "mongoose"; +import { Binary } from "mongodb"; + +const fileSchema = new mongoose.Schema({ + + length: { + type: Number, + required: true, + }, + chunkSize: { + type: Number, + }, + uploadDate: { + type: Date, + required: true + }, + filename: { + type: String, + required: true + }, + metadata: { + type: { + owner: { + type: String, + required: true + }, + parent: { + type: String, + required: true + }, + parentList: { + type: String, + required: true + }, + hasThumbnail: { + type: Boolean, + required: true + }, + isVideo: { + type: Boolean, + required: true + }, + thumbnailID: String, + size: { + type: Number, + required: true, + }, + IV: { + type: Binary, + required: true + }, + linkType: String, + link: String, + filePath: String + + }, + required: true + } + +}) + +export interface FileInterface extends Document { length: number, chunkSize: number, - updateDate: string, + uploadDate: string, filename: string, metadata: { owner: string, @@ -14,6 +74,12 @@ export interface FileInterface { size: number, IV: any, linkType?: 'one' | 'public', - link?: string + link?: string, + filePath?: string, } -} \ No newline at end of file +} + + +const File = mongoose.model("fs.files", fileSchema); + +export default File; \ No newline at end of file diff --git a/backend/models/fileSystem.ts b/backend/models/fileSystem.ts new file mode 100644 index 0000000..aaeebd6 --- /dev/null +++ b/backend/models/fileSystem.ts @@ -0,0 +1,69 @@ +import mongoose, {Document} from "mongoose"; + +const fileSystemSchema = new mongoose.Schema({ + + name: { + type: String, + required: true, + }, + owner: { + type: String, + required: true + }, + path: { + type: String, + required: true + }, + parent: { + type: String, + required: true, + }, + parentList: { + type: Array, + required: true + }, + hasThumbnail: { + type: Boolean, + required: true + }, + thumbnailID: { + type: String + }, + originalSize: { + type: Number, + required: true + }, + size: { + type: Number, + required: true + }, + isVideo: { + type: Boolean, + required: true + }, + IV: { + type: Buffer, + required: true + } + +}, { + timestamps: true +}) + +export interface FileSystemInterface extends Document { + name: string, + owner: string, + path: string, + parent: string, + parentList: string[], + hasThumbnail: boolean, + thumbnailID?: string, + originalSize: number, + size: number, + isVideo: boolean, + IV: Buffer +} + +const FileSystem = mongoose.model("FileSystem", fileSystemSchema); + +export default FileSystem; \ No newline at end of file diff --git a/backend/services/ChunkService/FileSystemService.ts b/backend/services/ChunkService/FileSystemService.ts new file mode 100644 index 0000000..1c3424d --- /dev/null +++ b/backend/services/ChunkService/FileSystemService.ts @@ -0,0 +1,113 @@ +import { Response, Request } from "express"; +import ChunkInterface from "./utils/ChunkInterface"; +import { UserInterface } from "../../models/user"; +import NotAuthorizedError from "../../utils/NotAuthorizedError"; +import NotFoundError from "../../utils/NotFoundError"; +import crypto from "crypto"; +import getBusboyData from "./utils/getBusboyData"; +import videoChecker from "../../utils/videoChecker"; +import fs from "fs"; +import uuid from "uuid"; +import awaitUploadStream from "./utils/awaitUploadStream"; +import File, { FileInterface } from "../../models/file"; +import getFileSize from "./utils/getFileSize"; +import DbUtilFile from "../../db/utils/fileUtils/index"; +import awaitStream from "./utils/awaitStream"; + +const dbUtilsFile = new DbUtilFile(); + +// implements ChunkInterface +class FileSystemService { + + constructor() { + + } + + uploadFile = async(user: UserInterface, busboy: any, req: Request) => { + + + const password = user.getEncryptionKey(); + + if (!password) throw new NotAuthorizedError("Invalid Encryption Key") + + + const initVect = crypto.randomBytes(16); + + const CIPHER_KEY = crypto.createHash('sha256').update(password).digest() + + const cipher = crypto.createCipheriv('aes256', CIPHER_KEY, initVect); + + const {file, filename, formData} = await getBusboyData(busboy); + + const parent = formData.get("parent") || "/" + const parentList = formData.get("parentList") || "/"; + const size = formData.get("size") || "" + let hasThumbnail = false; + let thumbnailID = "" + const isVideo = videoChecker(filename) + + const systemFileName = uuid.v4(); + + const metadata = { + owner: user._id, + parent, + parentList, + hasThumbnail, + thumbnailID, + isVideo, + size, + IV: initVect, + filePath: `/Users/kylehoell/Documents/fstestdata/${systemFileName}` + } + + const fileWriteStream = fs.createWriteStream(metadata.filePath); + + await awaitUploadStream(file.pipe(cipher), fileWriteStream, req); + + const date = new Date(); + const encryptedFileSize = await getFileSize(metadata.filePath); + + const currentFile = new File({ + filename, + uploadDate: date.toISOString(), + length: encryptedFileSize, + metadata + }); + + await currentFile.save(); + + console.log(currentFile); + + return currentFile; + + } + + downloadFile = async(user: UserInterface, fileID: string, res: Response) => { + + const currentFile: FileInterface = await dbUtilsFile.getFileInfo(fileID, user._id); + + if (!currentFile) throw new NotFoundError("Download File Not Found"); + + const password = user.getEncryptionKey(); + + if (!password) throw new NotAuthorizedError("Invalid Encryption Key") + + const filePath = currentFile.metadata.filePath!; + + const IV = currentFile.metadata.IV.buffer + + const readStream = fs.createReadStream(filePath); + + const CIPHER_KEY = crypto.createHash('sha256').update(password).digest() + + const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV); + + res.set('Content-Type', 'binary/octet-stream'); + res.set('Content-Disposition', 'attachment; filename="' + currentFile.filename + '"'); + res.set('Content-Length', currentFile.metadata.size.toString()); + + await awaitStream(readStream.pipe(decipher), res); + } +} + +export default FileSystemService; \ No newline at end of file diff --git a/backend/services/ChunkService/MongoService.ts b/backend/services/ChunkService/MongoService.ts index bbd7ef8..57e7f5e 100644 --- a/backend/services/ChunkService/MongoService.ts +++ b/backend/services/ChunkService/MongoService.ts @@ -22,10 +22,12 @@ import { Stream } from "stream"; import removeChunks from "../FileService/utils/removeChunks"; import getBusboyData from "./utils/getBusboyData"; +import ChunkInterface from "./utils/ChunkInterface"; + const dbUtilsFile = new DbUtilFile(); const dbUtilsFolder = new DbUtilFolder(); -class MongoService { +class MongoService implements ChunkInterface { constructor() { @@ -80,7 +82,6 @@ class MongoService { return updatedFile; - } else { return finishedFile; diff --git a/backend/services/ChunkService/utils/ChunkInterface.ts b/backend/services/ChunkService/utils/ChunkInterface.ts new file mode 100644 index 0000000..c335077 --- /dev/null +++ b/backend/services/ChunkService/utils/ChunkInterface.ts @@ -0,0 +1,14 @@ +import { UserInterface } from "../../../models/user"; +import { FileInterface } from "../../../models/file"; +import { Request, Response } from "express"; + +interface ChunkInterface { + uploadFile: (user: UserInterface, busboy: any, req: Request) => Promise; + downloadFile: (user: UserInterface, fileID: string, res: Response) => void; + getThumbnail: (user: UserInterface, id: string) => Promise; + getFullThumbnail: (user: UserInterface, fileID: string, res: Response) => void; + getPublicDownload: (fileID: string, tempToken: any, res: Response) => void; + streamVideo: (user: UserInterface, fileID: string, headers: any, res: Response) => void; +} + +export default ChunkInterface; \ No newline at end of file diff --git a/backend/services/ChunkService/utils/getFileSize.ts b/backend/services/ChunkService/utils/getFileSize.ts new file mode 100644 index 0000000..f493f6e --- /dev/null +++ b/backend/services/ChunkService/utils/getFileSize.ts @@ -0,0 +1,19 @@ +import fs from "fs"; + +const getFileSize = (path: string) => { + + return new Promise((resolve, reject) => { + + fs.stat(path, (error, stats) => { + + if (error) { + + resolve(0); + } + + resolve(stats.size); + }); + }) +} + +export default getFileSize; \ No newline at end of file diff --git a/dist/controllers/FileSystem/fileSystem.js b/dist/controllers/FileSystem/fileSystem.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/dist/controllers/FileSystem/fileSystem.js @@ -0,0 +1 @@ +"use strict"; diff --git a/dist/controllers/file.js b/dist/controllers/file.js index 79a6eb3..78889b3 100644 --- a/dist/controllers/file.js +++ b/dist/controllers/file.js @@ -17,6 +17,8 @@ const indexnew_1 = __importDefault(require("../services/FileService/indexnew")); const fileService = new indexnew_1.default(); const MongoService_1 = __importDefault(require("../services/ChunkService/MongoService")); const mongoService = new MongoService_1.default(); +const FileSystemService_1 = __importDefault(require("../services/ChunkService/FileSystemService")); +const fileSystemService = new FileSystemService_1.default(); class FileController { // fileService: ; constructor() { @@ -63,7 +65,7 @@ class FileController { const user = req.user; const busboy = req.busboy; req.pipe(busboy); - const file = yield mongoService.uploadFile(user, busboy, req); + const file = yield fileSystemService.uploadFile(user, busboy, req); res.send(file); console.log("file uploaded"); } @@ -342,7 +344,7 @@ class FileController { const user = req.user; const fileID = req.params.id; //await fileService.downloadFile(user, fileID, res); - yield mongoService.downloadFile(user, fileID, res); + yield fileSystemService.downloadFile(user, fileID, res); } catch (e) { const code = e.code || 500; diff --git a/dist/controllers/folder.js b/dist/controllers/folder.js index 73aed5a..630402d 100644 --- a/dist/controllers/folder.js +++ b/dist/controllers/folder.js @@ -8,6 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; +Object.defineProperty(exports, "__esModule", { value: true }); const FolderService = require("../services/FolderService"); const folderService = new FolderService(); class FolderController { diff --git a/dist/models/file.js b/dist/models/file.js index c8ad2e5..4f4a7e4 100644 --- a/dist/models/file.js +++ b/dist/models/file.js @@ -1,2 +1,63 @@ "use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); +const mongoose_1 = __importDefault(require("mongoose")); +const mongodb_1 = require("mongodb"); +const fileSchema = new mongoose_1.default.Schema({ + length: { + type: Number, + required: true, + }, + chunkSize: { + type: Number, + }, + uploadDate: { + type: Date, + required: true + }, + filename: { + type: String, + required: true + }, + metadata: { + type: { + owner: { + type: String, + required: true + }, + parent: { + type: String, + required: true + }, + parentList: { + type: String, + required: true + }, + hasThumbnail: { + type: Boolean, + required: true + }, + isVideo: { + type: Boolean, + required: true + }, + thumbnailID: String, + size: { + type: Number, + required: true, + }, + IV: { + type: mongodb_1.Binary, + required: true + }, + linkType: String, + link: String, + filePath: String + }, + required: true + } +}); +const File = mongoose_1.default.model("fs.files", fileSchema); +exports.default = File; diff --git a/dist/models/fileSystem.js b/dist/models/fileSystem.js new file mode 100644 index 0000000..458df75 --- /dev/null +++ b/dist/models/fileSystem.js @@ -0,0 +1,55 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const mongoose_1 = __importDefault(require("mongoose")); +const fileSystemSchema = new mongoose_1.default.Schema({ + name: { + type: String, + required: true, + }, + owner: { + type: String, + required: true + }, + path: { + type: String, + required: true + }, + parent: { + type: String, + required: true, + }, + parentList: { + type: Array, + required: true + }, + hasThumbnail: { + type: Boolean, + required: true + }, + thumbnailID: { + type: String + }, + originalSize: { + type: Number, + required: true + }, + size: { + type: Number, + required: true + }, + isVideo: { + type: Boolean, + required: true + }, + IV: { + type: Buffer, + required: true + } +}, { + timestamps: true +}); +const FileSystem = mongoose_1.default.model("FileSystem", fileSystemSchema); +exports.default = FileSystem; diff --git a/dist/services/ChunkService/FileSystemService.js b/dist/services/ChunkService/FileSystemService.js new file mode 100644 index 0000000..287f758 --- /dev/null +++ b/dist/services/ChunkService/FileSystemService.js @@ -0,0 +1,90 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const NotAuthorizedError_1 = __importDefault(require("../../utils/NotAuthorizedError")); +const NotFoundError_1 = __importDefault(require("../../utils/NotFoundError")); +const crypto_1 = __importDefault(require("crypto")); +const getBusboyData_1 = __importDefault(require("./utils/getBusboyData")); +const videoChecker_1 = __importDefault(require("../../utils/videoChecker")); +const fs_1 = __importDefault(require("fs")); +const uuid_1 = __importDefault(require("uuid")); +const awaitUploadStream_1 = __importDefault(require("./utils/awaitUploadStream")); +const file_1 = __importDefault(require("../../models/file")); +const getFileSize_1 = __importDefault(require("./utils/getFileSize")); +const index_1 = __importDefault(require("../../db/utils/fileUtils/index")); +const awaitStream_1 = __importDefault(require("./utils/awaitStream")); +const dbUtilsFile = new index_1.default(); +// implements ChunkInterface +class FileSystemService { + constructor() { + this.uploadFile = (user, busboy, req) => __awaiter(this, void 0, void 0, function* () { + const password = user.getEncryptionKey(); + if (!password) + throw new NotAuthorizedError_1.default("Invalid Encryption Key"); + const initVect = crypto_1.default.randomBytes(16); + const CIPHER_KEY = crypto_1.default.createHash('sha256').update(password).digest(); + const cipher = crypto_1.default.createCipheriv('aes256', CIPHER_KEY, initVect); + const { file, filename, formData } = yield getBusboyData_1.default(busboy); + const parent = formData.get("parent") || "/"; + const parentList = formData.get("parentList") || "/"; + const size = formData.get("size") || ""; + let hasThumbnail = false; + let thumbnailID = ""; + const isVideo = videoChecker_1.default(filename); + const systemFileName = uuid_1.default.v4(); + const metadata = { + owner: user._id, + parent, + parentList, + hasThumbnail, + thumbnailID, + isVideo, + size, + IV: initVect, + filePath: `/Users/kylehoell/Documents/fstestdata/${systemFileName}` + }; + const fileWriteStream = fs_1.default.createWriteStream(metadata.filePath); + yield awaitUploadStream_1.default(file.pipe(cipher), fileWriteStream, req); + const date = new Date(); + const encryptedFileSize = yield getFileSize_1.default(metadata.filePath); + const currentFile = new file_1.default({ + filename, + uploadDate: date.toISOString(), + length: encryptedFileSize, + metadata + }); + yield currentFile.save(); + console.log(currentFile); + return currentFile; + }); + this.downloadFile = (user, fileID, res) => __awaiter(this, void 0, void 0, function* () { + const currentFile = yield dbUtilsFile.getFileInfo(fileID, user._id); + if (!currentFile) + throw new NotFoundError_1.default("Download File Not Found"); + const password = user.getEncryptionKey(); + if (!password) + throw new NotAuthorizedError_1.default("Invalid Encryption Key"); + const filePath = currentFile.metadata.filePath; + const IV = currentFile.metadata.IV.buffer; + const readStream = fs_1.default.createReadStream(filePath); + const CIPHER_KEY = crypto_1.default.createHash('sha256').update(password).digest(); + const decipher = crypto_1.default.createDecipheriv('aes256', CIPHER_KEY, IV); + res.set('Content-Type', 'binary/octet-stream'); + res.set('Content-Disposition', 'attachment; filename="' + currentFile.filename + '"'); + res.set('Content-Length', currentFile.metadata.size.toString()); + yield awaitStream_1.default(readStream.pipe(decipher), res); + }); + } +} +exports.default = FileSystemService; diff --git a/dist/services/ChunkService/MongoService.js b/dist/services/ChunkService/MongoService.js index fda3cfb..10188e3 100644 --- a/dist/services/ChunkService/MongoService.js +++ b/dist/services/ChunkService/MongoService.js @@ -68,73 +68,6 @@ class MongoService { else { return finishedFile; } - // file.pipe(cipher).pipe(bucketStream); - // bucketStream.on("finish", (finishedFile: FileInterface) => { - // const imageCheck = imageChecker(filename); - // if (finishedFile.length < 15728640 && imageCheck) { - // createThumbnail(finishedFile, filename, user).then((updatedFile: FileInterface) => { - // resolve(updatedFile); - // }) - // } else { - // resolve(finishedFile); - // } - // }) - // return new Promise((resolve, reject) => { - // const password = user.getEncryptionKey(); - // if (!password) throw new NotAuthorizedError("Invalid Encryption Key") - // let bucketStream: GridFSBucketWriteStream; - // const initVect = crypto.randomBytes(16); - // const CIPHER_KEY = crypto.createHash('sha256').update(password).digest() - // const cipher = crypto.createCipheriv('aes256', CIPHER_KEY, initVect); - // const formData = new Map(); - // busboy.on("file", async(_: string, file: Stream, filename: string) => { - // const parent = formData.get("parent") || "/" - // const parentList = formData.get("parentList") || "/"; - // const size = formData.get("size") || "" - // let hasThumbnail = false; - // let thumbnailID = "" - // const isVideo = videoChecker(filename) - // const metadata = { - // owner: user._id, - // parent, - // parentList, - // hasThumbnail, - // thumbnailID, - // isVideo, - // size, - // IV: initVect - // } - // let bucket = new mongoose.mongo.GridFSBucket(conn.db, { - // chunkSizeBytes: 1024 * 255 - // }); - // bucketStream = bucket.openUploadStream(filename, {metadata}) - // bucketStream.on("error", async(e: Error) => { - // await removeChunks(bucketStream); - // reject({ - // message: "Cannot upload file to database", - // exception: e, - // code: 500 - // }) - // }) - // req.on("aborted", async() => { - // console.log("Upload Request Cancelling..."); - // await removeChunks(bucketStream); - // }) - // file.pipe(cipher).pipe(bucketStream); - // bucketStream.on("finish", (finishedFile: FileInterface) => { - // const imageCheck = imageChecker(filename); - // if (finishedFile.length < 15728640 && imageCheck) { - // createThumbnail(finishedFile, filename, user).then((updatedFile: FileInterface) => { - // resolve(updatedFile); - // }) - // } else { - // resolve(finishedFile); - // } - // }) - // }).on("field", (field: any, val: any) => { - // formData.set(field, val) - // }) - // }) }); this.downloadFile = (user, fileID, res) => __awaiter(this, void 0, void 0, function* () { const currentFile = yield dbUtilsFile.getFileInfo(fileID, user._id); @@ -152,45 +85,6 @@ class MongoService { res.set('Content-Disposition', 'attachment; filename="' + currentFile.filename + '"'); res.set('Content-Length', currentFile.metadata.size.toString()); yield awaitStream_1.default(readStream.pipe(decipher), res); - // return new Promise((resolve, reject) => { - // dbUtilsFile.getFileInfo(fileID, user._id).then((currentFile: FileInterface) => { - // if (!currentFile) { - // reject({ - // code: 401, - // message: "Download File Not Found Error", - // exception: undefined - // }) - // } else { - // const password = user.getEncryptionKey(); - // if (!password) throw new NotAuthorizedError("Invalid Encryption Key") - // const bucket = new mongoose.mongo.GridFSBucket(conn.db); - // const IV = currentFile.metadata.IV.buffer - // const readStream = bucket.openDownloadStream(new ObjectID(fileID)); - // readStream.on("error", (e: Error) => { - // reject({ - // code: 500, - // message: "File service download decipher error", - // exception: e - // }) - // }) - // const CIPHER_KEY = crypto.createHash('sha256').update(password).digest() - // const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV); - // decipher.on("error", (e) => { - // reject({ - // code: 500, - // message: "File service download decipher error", - // exception: e - // }) - // }) - // res.set('Content-Type', 'binary/octet-stream'); - // res.set('Content-Disposition', 'attachment; filename="' + currentFile.filename + '"'); - // res.set('Content-Length', currentFile.metadata.size.toString()); - // readStream.pipe(decipher).pipe(res).on("finish", () => { - // resolve(); - // }); - // } - // }) - // }) }); this.getThumbnail = (user, id) => __awaiter(this, void 0, void 0, function* () { const password = user.getEncryptionKey(); @@ -226,47 +120,6 @@ class MongoService { console.log("Sending Full Thumbnail..."); yield awaitStream_1.default(readStream.pipe(decipher), res); console.log("Full thumbnail sent"); - // return new Promise((resolve, reject) => { - // const userID = user._id; - // dbUtilsFile.getFileInfo(fileID, userID).then((file) => { - // if (!file) { - // reject({ - // code: 401, - // message: "File For Full Thumbnail Not Found", - // exception: undefined - // }) - // } - // const bucket = new mongoose.mongo.GridFSBucket(conn.db, { - // chunkSizeBytes: 1024 * 255, - // }) - // const password = user.getEncryptionKey(); - // const IV = file.metadata.IV.buffer - // const readStream = bucket.openDownloadStream(new ObjectID(fileID)) - // readStream.on("error", (e) => { - // reject({ - // code: 500, - // message: "File service Full Thumbnail stream error", - // exception: e - // }) - // }) - // const CIPHER_KEY = crypto.createHash('sha256').update(password).digest() - // const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV); - // decipher.on("error", (e) => { - // reject({ - // code: 500, - // message: "File service Full Thumbnail decipher error", - // exception: e - // }) - // }) - // res.set('Content-Type', 'binary/octet-stream'); - // res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"'); - // res.set('Content-Length', file.metadata.size); - // readStream.pipe(decipher).pipe(res).on("finish", () => { - // console.log("Sent Full Thumbnail"); - // resolve(); - // }); - // }); - // }) }); this.getPublicDownload = (fileID, tempToken, res) => __awaiter(this, void 0, void 0, function* () { const file = yield dbUtilsFile.getPublicFile(fileID); @@ -325,62 +178,6 @@ class MongoService { const decipher = crypto_1.default.createDecipheriv('aes256', CIPHER_KEY, IV); res.writeHead(206, head); yield awaitStream_1.default(readStream.pipe(decipher), res); - // return new Promise((resolve, reject) => { - // const userID = user._id; - // dbUtilsFile.getFileInfo(fileID, userID).then((currentFile: FileInterface) => { - // if (!currentFile) { - // reject({ - // code: 401, - // message: "Video Steam Not Found Error", - // exception: undefined - // }) - // } else { - // const password = user.getEncryptionKey(); - // if (!password) throw new NotAuthorizedError("Invalid Encryption Key") - // const fileSize = currentFile.metadata.size; - // const range = headers.range - // const parts = range.replace(/bytes=/, "").split("-") - // let start = parseInt(parts[0], 10) - // let end = parts[1] - // ? parseInt(parts[1], 10) - // : fileSize-1 - // const chunksize = (end-start)+1 - // const IV = currentFile.metadata.IV.buffer - // let head = { - // 'Content-Range': 'bytes ' + start + '-' + end + '/' + fileSize, - // 'Accept-Ranges': 'bytes', - // 'Content-Length': chunksize, - // 'Content-Type': 'video/mp4'} - // const bucket = new mongoose.mongo.GridFSBucket(conn.db, { - // chunkSizeBytes: 1024 - // }); - // const readStream = bucket.openDownloadStream(new ObjectID(fileID), { - // start: start, - // end: end - // }); - // readStream.on("error", (e) => { - // reject({ - // code: 500, - // message: "File service stream video stream error", - // exception: e - // }) - // }) - // const CIPHER_KEY = crypto.createHash('sha256').update(password).digest() - // const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV); - // decipher.on("error", (e) => { - // reject({ - // code: 500, - // message: "File service stream video decipher error", - // exception: e - // }) - // }) - // res.writeHead(206, head); - // readStream.pipe(decipher).pipe(res).on("finish", () => { - // resolve(); - // }); - // } - // }) - // }) }); } } diff --git a/dist/services/ChunkService/utils/ChunkInterface.js b/dist/services/ChunkService/utils/ChunkInterface.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/dist/services/ChunkService/utils/ChunkInterface.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/services/ChunkService/utils/getFileSize.js b/dist/services/ChunkService/utils/getFileSize.js new file mode 100644 index 0000000..0ca261c --- /dev/null +++ b/dist/services/ChunkService/utils/getFileSize.js @@ -0,0 +1,17 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const fs_1 = __importDefault(require("fs")); +const getFileSize = (path) => { + return new Promise((resolve, reject) => { + fs_1.default.stat(path, (error, stats) => { + if (error) { + resolve(0); + } + resolve(stats.size); + }); + }); +}; +exports.default = getFileSize; diff --git a/package.json b/package.json index 36f2029..7d55069 100755 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@types/mongodb": "^3.5.5", "@types/mongoose": "^5.7.10", "@types/node": "^13.11.1", + "@types/uuid": "^7.0.2", "axios": "^0.19.2", "babel-polyfill": "^6.26.0", "bcrypt": "^3.0.8",