diff --git a/.DS_Store b/.DS_Store index 7c761f1..d99ca88 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/backend/controllers/file.js b/backend/controllers/file.ts similarity index 56% rename from backend/controllers/file.js rename to backend/controllers/file.ts index 42ff660..f55db61 100644 --- a/backend/controllers/file.js +++ b/backend/controllers/file.ts @@ -1,15 +1,32 @@ -const FileService = require("../services/FileService") +import { Request, Response } from "express"; + +//const FileService = require("../services/FileService") +import FileService from "../services/FileService/indexnew"; const fileService = new FileService() + +import MongoService from "../services/ChunkService/MongoService"; +const mongoService = new MongoService(); + +import {UserInterface} from "../models/user"; + +interface RequestType extends Request { + user?: UserInterface, + auth?: any, + busboy?: any, +} + class FileController { + // fileService: ; + constructor() { } + getThumbnail = async(req: RequestType, res: Response) => { - async getThumbnail(req, res) { if (!req.user) { @@ -17,6 +34,7 @@ class FileController { } try { + const user = req.user; const id = req.params.id; @@ -35,73 +53,73 @@ class FileController { } - async getFullThumbnail(req, res) { + // async getFullThumbnail(req: RequestType, res: Response) { - if (!req.user) { - return; - } + // if (!req.user) { + // return; + // } - try { + // try { - const user = req.user; - const fileID = req.params.id; + // const user = req.user; + // const fileID = req.params.id; - await fileService.getFullThumbnail(user, fileID, res); + // await fileService.getFullThumbnail(user, fileID, res); - } catch (e) { - const code = e.code || 500; - console.log(e.message, e.exception) - return res.status(code).send(); - } - } + // } catch (e) { + // const code = e.code || 500; + // console.log(e.message, e.exception) + // return res.status(code).send(); + // } + // } - async uploadFile(req, res) { + // async uploadFile(req: RequestType, res: Response) { - if (!req.user) { + // if (!req.user) { - return - } + // return + // } - try { + // try { - const user = req.user; - const busboy = req.busboy; + // const user = req.user; + // const busboy = req.busboy; - req.pipe(busboy); + // req.pipe(busboy); - const file = await fileService.upload(user, busboy, req); + // const file = await fileService.upload(user, busboy, req); - res.send(file); + // res.send(file); - console.log("file uploaded"); + // console.log("file uploaded"); - } catch (e) { - const code = e.code || 500; - console.log(e.message, e.exception) - return res.status(code).send(); - } - } + // } catch (e) { + // const code = e.code || 500; + // console.log(e.message, e.exception) + // return res.status(code).send(); + // } + // } - async getPublicDownload(req, res) { + // async getPublicDownload(req: RequestType, res: Response) { - try { + // try { - const ID = req.params.id; - const tempToken = req.params.tempToken; + // const ID = req.params.id; + // const tempToken = req.params.tempToken; - await fileService.publicDownload(ID, tempToken, res); + // await fileService.publicDownload(ID, tempToken, res); - } catch (e) { + // } catch (e) { - const code = e.code || 500; - const message = e.message || e; + // const code = e.code || 500; + // const message = e.message || e; - console.log(message, e); - res.status(code).send(); - } - } + // console.log(message, e); + // res.status(code).send(); + // } + // } - async removeLink(req, res) { + async removeLink(req: RequestType, res: Response) { if (!req.user) { return; @@ -126,7 +144,7 @@ class FileController { } - async makePublic(req, res) { + async makePublic(req: RequestType, res: Response) { if (!req.user) { return; @@ -150,7 +168,7 @@ class FileController { } } - async getPublicInfo(req, res) { + async getPublicInfo(req: RequestType, res: Response) { try { @@ -170,7 +188,7 @@ class FileController { } } - async makeOneTimePublic(req, res) { + async makeOneTimePublic(req: RequestType, res: Response) { if (!req.user) { return; @@ -195,7 +213,7 @@ class FileController { } - async getFileInfo(req, res) { + async getFileInfo(req: RequestType, res: Response) { if (!req.user) { return; @@ -219,7 +237,7 @@ class FileController { } } - async getQuickList(req, res) { + async getQuickList(req: RequestType, res: Response) { if (!req.user) { return; @@ -242,7 +260,7 @@ class FileController { } } - async getList(req, res) { + async getList(req: RequestType, res: Response) { if (!req.user) { return @@ -266,7 +284,7 @@ class FileController { } } - async getDownloadToken(req, res) { + async getDownloadToken(req: RequestType, res: Response) { if (!req.user) { return @@ -289,7 +307,7 @@ class FileController { } } - async getDownloadTokenVideo(req, res) { + async getDownloadTokenVideo(req: RequestType, res: Response) { if (!req.user) { return @@ -298,7 +316,7 @@ class FileController { try { const user = req.user; - const cookie = req.headers.uuid + const cookie = req.headers.uuid as string; const tempToken = await fileService.getDownloadTokenVideo(user, cookie); @@ -313,7 +331,7 @@ class FileController { } } - async removeTempToken(req, res) { + async removeTempToken(req: RequestType, res: Response) { if (!req.user) { return @@ -337,111 +355,111 @@ class FileController { } } - async transcodeVideo(req, res) { + // async transcodeVideo(req: RequestType, res: Response) { - if (!req.user) { + // if (!req.user) { - return; - } + // return; + // } - try { + // try { - console.log("transcode request", req.body.file._id) + // console.log("transcode request", req.body.file._id) - const user = req.user; - const body = req.body; + // const user = req.user; + // const body = req.body; - await fileService.transcodeVideo(user, body); + // await fileService.transcodeVideo(user, body); - res.send("Finished"); + // res.send("Finished"); - } catch (e) { + // } catch (e) { - const code = e.code || 500; - console.log(e.message, e.exception) - return res.status(code).send(); - } - } + // const code = e.code || 500; + // console.log(e.message, e.exception) + // return res.status(code).send(); + // } + // } - async removeTranscodeVideo(req, res) { + // async removeTranscodeVideo(req: RequestType, res: Response) { - if (!req.user) { + // if (!req.user) { - return; - } + // return; + // } - try { + // try { - const fileID = req.body.id; - const userID = req.user._id; + // const fileID = req.body.id; + // const userID = req.user._id; - await fileService.removeTranscodeVideo(userID, fileID); + // await fileService.removeTranscodeVideo(userID, fileID); - res.send(); + // res.send(); - } catch (e) { + // } catch (e) { - const code = e.code || 500; + // const code = e.code || 500; - console.log(e); - res.status(code).send() - } - } + // console.log(e); + // res.status(code).send() + // } + // } - async streamTranscodedVideo(req, res) { + // async streamTranscodedVideo(req: RequestType, res: Response) { - if (!req.auth || !req.user) { - return; - } + // if (!req.auth || !req.user) { + // return; + // } - try { + // try { - console.log("stream request transcoded", req.params.id) + // console.log("stream request transcoded", req.params.id) - const fileID = req.params.id; - const userID = req.user._id; - const headers = req.headers; + // const fileID = req.params.id; + // const userID = req.user._id; + // const headers = req.headers; - await fileService.streamTranscodedVideo(userID, fileID, headers, res); + // await fileService.streamTranscodedVideo(userID, fileID, headers, res); - } catch (e) { + // } catch (e) { - const code = e.code || 500; - const message = e.message || e; + // const code = e.code || 500; + // const message = e.message || e; - console.log(message, e); - res.status(code).send(); - } - } + // console.log(message, e); + // res.status(code).send(); + // } + // } - async streamVideo(req, res) { + // async streamVideo(req: RequestType, res: Response) { - if (!req.auth || !req.user) { - return; - } + // if (!req.auth || !req.user) { + // return; + // } - try { + // try { - const user = req.user; - const fileID = req.params.id; - const headers = req.headers; + // const user = req.user; + // const fileID = req.params.id; + // const headers = req.headers; - console.log("stream request", req.params.id) + // console.log("stream request", req.params.id) - await fileService.streamVideo(user, fileID, headers, res); + // await fileService.streamVideo(user, fileID, headers, res); - } catch (e) { + // } catch (e) { - const code = e.code || 500; - const message = e.message || e; + // const code = e.code || 500; + // const message = e.message || e; - console.log(message, e); - res.status(code).send(); - } + // console.log(message, e); + // res.status(code).send(); + // } - } + // } - async downloadFile(req, res) { + async downloadFile(req: RequestType, res: Response) { if (!req.auth || !req.user) { return; @@ -454,7 +472,8 @@ class FileController { const user = req.user; const fileID = req.params.id; - await fileService.downloadFile(user, fileID, res); + //await fileService.downloadFile(user, fileID, res); + await mongoService.downloadFile(user, fileID, res); } catch (e) { @@ -466,7 +485,7 @@ class FileController { } } - async getSuggestedList(req, res) { + async getSuggestedList(req: RequestType, res: Response) { if (!req.user) { return; @@ -491,7 +510,7 @@ class FileController { } } - async renameFile(req, res) { + async renameFile(req: RequestType, res: Response) { if (!req.user) { return; @@ -517,7 +536,7 @@ class FileController { } - async moveFile(req, res) { + async moveFile(req: RequestType, res: Response) { console.log("move request"); @@ -547,7 +566,7 @@ class FileController { } - async deleteFile(req, res) { + async deleteFile(req: RequestType, res: Response) { if (!req.user) { return; @@ -572,4 +591,4 @@ class FileController { } } -module.exports = FileController; +export default FileController; diff --git a/backend/express-routers/file.js b/backend/express-routers/file.ts similarity index 65% rename from backend/express-routers/file.js rename to backend/express-routers/file.ts index f9f9860..35d46e4 100644 --- a/backend/express-routers/file.js +++ b/backend/express-routers/file.ts @@ -1,21 +1,24 @@ -const express = require("express"); -const router = new express.Router; +import {Router} from "express"; + +const router = Router(); + const auth = require("../middleware/auth"); const tempAuth = require("../middleware/tempAuth") const tempAuthVideo = require("../middleware/tempAuthVideo") -const FileController = require("../controllers/file"); + +import FileController from "../controllers/file"; const fileController = new FileController() -router.post("/file-service/upload", auth, fileController.uploadFile); +//router.post("/file-service/upload", auth, fileController.uploadFile); -router.post("/file-service/transcode-video", auth, fileController.transcodeVideo); +//router.post("/file-service/transcode-video", auth, fileController.transcodeVideo); router.get("/file-service/thumbnail/:id", auth, fileController.getThumbnail); -router.get("/file-service/full-thumbnail/:id", auth, fileController.getFullThumbnail); +//router.get("/file-service/full-thumbnail/:id", auth, fileController.getFullThumbnail); -router.get("/file-service/public/download/:id/:tempToken", fileController.getPublicDownload); +//router.get("/file-service/public/download/:id/:tempToken", fileController.getPublicDownload); router.get("/file-service/public/info/:id/:tempToken", fileController.getPublicInfo); @@ -29,9 +32,9 @@ router.get("/file-service/download/get-token", auth, fileController.getDownloadT router.get("/file-service/download/get-token-video", auth, fileController.getDownloadTokenVideo); -router.get("/file-service/stream-video-transcoded/:id/:tempToken/:uuid", tempAuthVideo, fileController.streamTranscodedVideo); +//router.get("/file-service/stream-video-transcoded/:id/:tempToken/:uuid", tempAuthVideo, fileController.streamTranscodedVideo); -router.get("/file-service/stream-video/:id/:tempToken/:uuid", tempAuthVideo, fileController.streamVideo); +//router.get("/file-service/stream-video/:id/:tempToken/:uuid", tempAuthVideo, fileController.streamVideo); router.get("/file-service/download/:id/:tempToken", tempAuth, fileController.downloadFile); @@ -49,7 +52,7 @@ router.delete("/file-service/remove-link/:id", auth, fileController.removeLink); router.delete("/file-service/remove/token-video/:tempToken", auth, fileController.removeTempToken); -router.delete("/file-service/transcode-video/remove", auth, fileController.removeTranscodeVideo); +//router.delete("/file-service/transcode-video/remove", auth, fileController.removeTranscodeVideo); router.delete("/file-service/remove", auth, fileController.deleteFile); diff --git a/backend/express-routers/folder.js b/backend/express-routers/folder.ts similarity index 89% rename from backend/express-routers/folder.js rename to backend/express-routers/folder.ts index 117be38..69a9dce 100644 --- a/backend/express-routers/folder.js +++ b/backend/express-routers/folder.ts @@ -1,5 +1,5 @@ -const express = require("express"); -const router = new express.Router; +import {Router} from "express"; +const router = Router(); const auth = require("../middleware/auth"); const FolderController = require("../controllers/folder"); const folderController = new FolderController(); diff --git a/backend/express-routers/storage.js b/backend/express-routers/storage.ts similarity index 71% rename from backend/express-routers/storage.js rename to backend/express-routers/storage.ts index 5fa436b..f5a4966 100644 --- a/backend/express-routers/storage.js +++ b/backend/express-routers/storage.ts @@ -1,5 +1,5 @@ -const express = require("express"); -const router = new express.Router; +import {Router} from "express"; +const router = Router(); const auth = require("../middleware/auth"); const StorageController = require("../controllers/storage"); const storageController = new StorageController(); diff --git a/backend/express-routers/user.js b/backend/express-routers/user.ts similarity index 85% rename from backend/express-routers/user.js rename to backend/express-routers/user.ts index 089a4ff..3a376de 100644 --- a/backend/express-routers/user.js +++ b/backend/express-routers/user.ts @@ -1,5 +1,5 @@ -const express = require("express"); -const router = new express.Router; +import {Router} from "express"; +const router = Router(); const auth = require("../middleware/auth"); const UserController = require("../controllers/user"); const userController = new UserController(); diff --git a/backend/key/getKey.js b/backend/key/getKey.js new file mode 100644 index 0000000..533b36f --- /dev/null +++ b/backend/key/getKey.js @@ -0,0 +1,30 @@ +const prompt = require('password-prompt') +const env = require("../enviroment/env"); +const crypto = require("crypto"); + +const getKey = async() => { + + if (process.env.KEY) { + // For Docker + + env.key = process.env.KEY + + } else if (process.env.NODE_ENV) { + + let password = await prompt("Enter Server Encryption Password: ", {method: "hide"}); + + password = crypto.createHash("md5").update(password).digest("hex"); + + env.key = password; + + } else { + + let password = "1234"; + + password = crypto.createHash("md5").update(password).digest("hex"); + + env.key = password; + } +} + +module.exports = getKey; \ No newline at end of file diff --git a/backend/models/file.ts b/backend/models/file.ts new file mode 100644 index 0000000..a03af91 --- /dev/null +++ b/backend/models/file.ts @@ -0,0 +1,19 @@ +export interface FileInterface { + _id: string, + length: number, + chunkSize: number, + updateDate: string, + filename: string, + metadata: { + owner: string, + parent: string, + parentList: string, + hasThumbnail: boolean, + isVideo: boolean, + thumbnailID?: string, + size: number, + IV: any, + linkType?: 'one' | 'public', + link?: string + } +} \ No newline at end of file diff --git a/backend/models/thumbnail.js b/backend/models/thumbnail.ts similarity index 50% rename from backend/models/thumbnail.js rename to backend/models/thumbnail.ts index fe873c9..7fbc73c 100644 --- a/backend/models/thumbnail.js +++ b/backend/models/thumbnail.ts @@ -1,4 +1,4 @@ -const mongoose = require("mongoose"); +import mongoose, {Document} from "mongoose"; const thumbnailSchema = new mongoose.Schema({ @@ -20,6 +20,13 @@ const thumbnailSchema = new mongoose.Schema({ timestamps: true }) -const Thumbnail = mongoose.model("Thumbnail", thumbnailSchema); +export interface ThumbnailInterface extends Document { + _id: string, + name: string, + owner: string, + data: any +} -module.exports = Thumbnail; \ No newline at end of file +const Thumbnail = mongoose.model("Thumbnail", thumbnailSchema); + +export default Thumbnail; \ No newline at end of file diff --git a/backend/models/user.js b/backend/models/user.ts similarity index 87% rename from backend/models/user.js rename to backend/models/user.ts index 4c90626..0ee9243 100644 --- a/backend/models/user.js +++ b/backend/models/user.ts @@ -1,11 +1,11 @@ -const mongoose = require("mongoose"); +import mongoose, {Document} from "mongoose"; const validator = require("validator"); const crypto = require("crypto"); const bcrypt = require("bcrypt"); const jwt = require("jsonwebtoken"); const env = require("../enviroment/env"); -const userSchema = mongoose.Schema({ +const userSchema = new mongoose.Schema({ name: { @@ -18,7 +18,7 @@ const userSchema = mongoose.Schema({ trim: true, unique: true, lowercase: true, - validate(value) { + validate(value: any): any { if (!validator.isEmail(value)) { throw new Error("Email is invalid"); } @@ -28,7 +28,7 @@ const userSchema = mongoose.Schema({ type: String, trim: true, required: true, - validate(value) { + validate(value: any): any { if (value.length < 6) { throw new Error("Password Length Not Sufficent"); } @@ -57,12 +57,30 @@ const userSchema = mongoose.Schema({ timestamps: true }) +export interface UserInterface extends Document { + _id: string, + name: string, + email: string, + password: string, + tokens: any[], + tempTokens: any[], + privateKey?: string, + publicKey?: string, + token?:string, + + getEncryptionKey: () => Buffer; + generateTempAuthToken: () => any; + generateTempAuthTokenVideo: (cookie: string) => any; + encryptToken: (tempToken: any, key: any, publicKey: any) => any; +} + // userSchema.virtual("files", { // ref: "fs.files", // localField: "_id" // }) -userSchema.pre("save", async function(next) { + +userSchema.pre("save", async function(this: any, next: any) { const user = this; @@ -73,7 +91,7 @@ userSchema.pre("save", async function(next) { next(); }) -userSchema.statics.findByCreds = async(email, password) => { +userSchema.statics.findByCreds = async(email: string, password: string) => { const user = await User.findOne({email}); @@ -123,7 +141,7 @@ userSchema.methods.generateAuthToken = async function() { return token; } -userSchema.methods.encryptToken = function(token, key, iv) { +userSchema.methods.encryptToken = function(token: string, key: string, iv: any) { iv = Buffer.from(iv, "hex") @@ -135,7 +153,7 @@ userSchema.methods.encryptToken = function(token, key, iv) { return encryptedText; } -userSchema.methods.decryptToken = function(encryptedToken, key, iv) { +userSchema.methods.decryptToken = function(encryptedToken: any, key: string, iv: any) { encryptedToken = Buffer.from(encryptedToken, "hex"); iv = Buffer.from(iv, "hex") @@ -197,7 +215,7 @@ userSchema.methods.getEncryptionKey = function() { return decrypted; } -userSchema.methods.changeEncryptionKey = async function(randomKey) { +userSchema.methods.changeEncryptionKey = async function(randomKey: string) { const user = this; const userPassword = user.password; @@ -251,7 +269,7 @@ userSchema.methods.generateTempAuthToken = async function() { return token; } -userSchema.methods.generateTempAuthTokenVideo = async function(cookie) { +userSchema.methods.generateTempAuthTokenVideo = async function(cookie: string) { const iv = crypto.randomBytes(16); @@ -270,6 +288,6 @@ userSchema.methods.generateTempAuthTokenVideo = async function(cookie) { } -const User = mongoose.model("User", userSchema); +const User = mongoose.model("User", userSchema); module.exports = User; \ No newline at end of file diff --git a/server/server.js b/backend/server/server.js similarity index 80% rename from server/server.js rename to backend/server/server.js index 3f7aaab..4fdc033 100755 --- a/server/server.js +++ b/backend/server/server.js @@ -1,11 +1,11 @@ const express = require("express"); const app = express(); const path = require("path") -const publicPath = path.join(__dirname, "..", "public"); -const userRouter = require("../backend/express-routers/user") -const fileRouter = require("../backend/express-routers/file") -const folderRouter = require("../backend/express-routers/folder"); -const storageRouter = require("../backend/express-routers/storage"); +const publicPath = path.join(__dirname, "..", "..", "public"); +const userRouter = require("../express-routers/user") +const fileRouter = require("../express-routers/file") +const folderRouter = require("../express-routers/folder"); +const storageRouter = require("../express-routers/storage"); const bodyParser = require('body-parser'); const https = require("https"); const fs = require("fs"); @@ -39,7 +39,7 @@ server = http.createServer(app); -require("../backend/db/mongoose"); +require("../db/mongoose"); app.use(helmet()) diff --git a/server/serverStart.js b/backend/server/serverStart.js similarity index 100% rename from server/serverStart.js rename to backend/server/serverStart.js diff --git a/backend/services/ChunkService/MongoService.ts b/backend/services/ChunkService/MongoService.ts new file mode 100644 index 0000000..ecd9830 --- /dev/null +++ b/backend/services/ChunkService/MongoService.ts @@ -0,0 +1,81 @@ +import mongoose from "../../db/mongoose"; +import {Response} from "express"; +const conn = mongoose.connection; +const env = require("../../enviroment/env"); +const DbUtilFolder = require("../../db/utils/folderUtils"); +import DbUtilFile from "../../db/utils/fileUtils/index"; +import crypto from "crypto"; + +const ObjectID = require('mongodb').ObjectID + +import { UserInterface } from "../../models/user"; +import { FileInterface } from "../../models/file"; + +const dbUtilsFile = new DbUtilFile(); +const dbUtilsFolder = new DbUtilFolder(); + +class MongoService { + + constructor() { + + } + + downloadFile = (user: UserInterface, fileID: string, res: Response) => { + + 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: Buffer = user.getEncryptionKey(); + + const bucket = new mongoose.mongo.GridFSBucket(conn.db); + + const IV = currentFile.metadata.IV.buffer + const readStream = bucket.openDownloadStream(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(); + }); + } + + }) + }) + } + +} + +export default MongoService; \ No newline at end of file diff --git a/backend/services/FileService/index.js b/backend/services/FileService/index.js index 4c5838b..abe4686 100644 --- a/backend/services/FileService/index.js +++ b/backend/services/FileService/index.js @@ -1,13 +1,13 @@ -const imageChecker = require("../../../src/utils/imageChecker"); -const crypto= require("crypto"); -const videoChecker = require("../../../src/utils/videoChecker"); +const imageChecker = require("../../utils/imageChecker"); +import crypto from "crypto"; +const videoChecker = require("../../utils/videoChecker"); const mongoose = require("../../db/mongoose") const conn = mongoose.connection; -const createThumbnail = require("../../services/FileService/utils/createThumbnail"); +const createThumbnail = require("./utils/createThumbnail"); const Thumbnail = require("../../models/thumbnail"); const ObjectID = require('mongodb').ObjectID -const NotAuthorizedError = require("../../../src/utils/NotAuthorizedError"); -const NotFoundError = require("../../../src/utils/NotFoundError"); +const NotAuthorizedError = require("../../utils/NotAuthorizedError"); +const NotFoundError = require("../../utils/NotFoundError"); const env = require("../../enviroment/env"); const jwt = require("jsonwebtoken"); const removeChunks = require("./utils/removeChunks"); @@ -15,8 +15,8 @@ const User = require("../../models/user"); const Folder = require("../../models/folder"); -const sortBySwitch = require("../../../src/utils/sortBySwitch") -const createQuery = require("../../../src/utils/createQuery"); +const sortBySwitch = require("../../utils/sortBySwitch") +const createQuery = require("../../utils/createQuery"); const ffmpeg = require("fluent-ffmpeg"); const temp = require("temp").track(); const progress = require("progress-stream"); diff --git a/backend/services/FileService/indexnew.ts b/backend/services/FileService/indexnew.ts new file mode 100644 index 0000000..7092fdc --- /dev/null +++ b/backend/services/FileService/indexnew.ts @@ -0,0 +1,286 @@ +const imageChecker = require("../../utils/imageChecker"); +import crypto from "crypto"; +const videoChecker = require("../../utils/videoChecker"); +const mongoose = require("../../db/mongoose") +const conn = mongoose.connection; +const createThumbnail = require("../../services/FileService/utils/createThumbnail"); +import Thumbnail, {ThumbnailInterface} from "../../models/thumbnail"; +const ObjectID = require('mongodb').ObjectID +import NotAuthorizedError from "../../utils/NotAuthorizedError"; +import NotFoundError from "../../utils/NotFoundError"; +const env = require("../../enviroment/env"); +const jwt = require("jsonwebtoken"); +const removeChunks = require("./utils/removeChunks"); +const User = require("../../models/user"); + + +const Folder = require("../../models/folder"); +const sortBySwitch = require("../../utils/sortBySwitch") +const createQuery = require("../../utils/createQuery"); +const ffmpeg = require("fluent-ffmpeg"); +const temp = require("temp").track(); +const progress = require("progress-stream"); +const fs = require("fs") +import DbUtilFile from "../../db/utils/fileUtils/index"; +const DbUtilFolder = require("../../db/utils/folderUtils"); + +const dbUtilsFile = new DbUtilFile(); +const dbUtilsFolder = new DbUtilFolder(); + +import { UserInterface } from "../../models/user"; +import { FileInterface } from "../../models/file"; + +class MongoFileService { + + constructor() { + + } + + getThumbnail = async(user: UserInterface, id: string) => { + + const password: Buffer = user.getEncryptionKey(); + + const thumbnail = await Thumbnail.findById(id) as ThumbnailInterface; + + if (thumbnail.owner !== user._id.toString()) { + + throw new NotAuthorizedError('Thumbnail Unauthorized Error'); + } + + const iv = thumbnail.data.slice(0, 16); + + const chunk = thumbnail.data.slice(16); + + const CIPHER_KEY = crypto.createHash('sha256').update(password).digest() + + const decipher = crypto.createDecipheriv("aes256", CIPHER_KEY, iv); + + const decryptedThumbnail = Buffer.concat([decipher.update(chunk), decipher.final()]); + + return decryptedThumbnail; + } + + removePublicOneTimeLink = async(currentFile: FileInterface) => { + + const fileID = currentFile._id; + + if (currentFile.metadata.linkType === "one") { + + await dbUtilsFile.removeOneTimePublicLink(fileID); + } + } + + removeLink = async(userID: string, fileID: string) => { + + const file = await dbUtilsFile.removeLink(fileID, userID); + + if (!file.lastErrorObject.updatedExisting) throw new NotFoundError("Remove Link File Not Found Error") + } + + makePublic = async(user: UserInterface, fileID: string) => { + + const userID = user._id; + const token = await jwt.sign({_id: userID.toString()}, env.password); + + const file = await dbUtilsFile.makePublic(fileID, userID, token); + + if (!file.lastErrorObject.updatedExisting) throw new NotFoundError("Make Public File Not Found Error"); + + return token; + } + + getPublicInfo = async(fileID: string, tempToken: string) => { + + const file: FileInterface = await dbUtilsFile.getPublicInfo(fileID, tempToken); + + if (!file || !file.metadata.link || file.metadata.link !== tempToken) { + + throw new NotFoundError("Public Info Not Found"); + + } else { + + return file; + } + } + + makeOneTimePublic = async(userID: string, fileID: string) => { + + const token = await jwt.sign({_id: userID.toString()}, env.password); + + const file = await dbUtilsFile.makeOneTimePublic(fileID, userID, token); + + if (!file.lastErrorObject.updatedExisting) throw new NotFoundError("Make One Time Public Not Found Error"); + + return token; + } + + getFileInfo = async(userID: string, fileID: string) => { + + let currentFile = await dbUtilsFile.getFileInfo(fileID, userID) + + if (!currentFile) throw new NotFoundError("Get File Info Not Found Error"); + + const parentID = currentFile.metadata.parent + + let parentName = ""; + + if (parentID === "/") { + + parentName = "Home" + + } else { + + const parentFolder = await Folder.findOne({"owner": userID, "_id": parentID}); + + if (parentFolder) { + + parentName = parentFolder.name; + + } else { + + parentName = "Unknown" + } + + } + + return {...currentFile, parentName} + } + + getQuickList = async(userID: string) => { + + const quickList = await dbUtilsFile.getQuickList(userID); + + if (!quickList) throw new NotFoundError("Quick List Not Found Error"); + + return quickList; + } + + getList = async(userID: string, query: any) => { + + let searchQuery = query.search || ""; + const parent = query.parent || "/"; + let limit = query.limit || 50; + let sortBy = query.sortby || "DEFAULT" + const startAt = query.startAt || undefined + const startAtDate = query.startAtDate || "0" + const startAtName = query.startAtName || "" + sortBy = sortBySwitch(sortBy) + limit = parseInt(limit) + + const queryObj = createQuery(userID, parent, query.sortby,startAt, startAtDate, searchQuery, startAtName) + + const fileList = await dbUtilsFile.getList(queryObj, sortBy, limit); + + if (!fileList) throw new NotFoundError("File List Not Found"); + + return fileList; + } + + getDownloadToken = async(user: UserInterface) => { + + const tempToken = await user.generateTempAuthToken(); + + if (!tempToken) throw new NotAuthorizedError("Get Download Token Not Authorized Error"); + + return tempToken; + } + + getDownloadTokenVideo = async(user: UserInterface, cookie: string) => { + + if (!cookie) throw new NotAuthorizedError("Get Download Token Video Cookie Not Authorized Error"); + + const tempToken = await user.generateTempAuthTokenVideo(cookie); + + if (!tempToken) throw new NotAuthorizedError("Get Download Token Video Not Authorized Error"); + + return tempToken; + } + + removeTempToken = async(user: UserInterface, tempToken: any) => { + + const key = user.getEncryptionKey(); + + const decoded = await jwt.verify(tempToken, env.password); + + const publicKey = decoded.iv; + + const encryptedToken = user.encryptToken(tempToken, key, publicKey); + + const removedTokenUser = await dbUtilsFile.removeTempToken(user, encryptedToken); + + if (!removedTokenUser) throw new NotFoundError("Remove Temp Token User Not Found Errors"); + + await removedTokenUser.save(); + } + + getSuggestedList = async(userID: string, searchQuery: any) => { + + searchQuery = new RegExp(searchQuery, 'i') + + const fileList = await dbUtilsFile.getFileSearchList(userID, searchQuery); + const folderList = await dbUtilsFolder.getFolderSearchList(userID, searchQuery); + + if (!fileList || !folderList) throw new NotFoundError("Suggested List Not Found Error"); + + return { + fileList, + folderList + } + } + + renameFile = async(userID: string, fileID: string, title: string) => { + + const file = await dbUtilsFile.renameFile(fileID, userID, title); + + if (!file.lastErrorObject.updatedExisting) throw new NotFoundError("Rename File Not Found Error"); + + return file; + } + + moveFile = async(userID: string, fileID: string, parentID: string) => { + + let parentList = ["/"]; + + if (parentID.length !== 1) { + + const parentFile = await dbUtilsFolder.getFolderInfo(parentID, userID); + if (!parentFile) throw new NotFoundError("Rename Parent File Not Found Error") + const parentList = parentFile.parentList; + parentList.push(parentID); + } + + const file = await dbUtilsFile.moveFile(fileID, userID, parentID, parentList.toString()); + + if (!file.lastErrorObject.updatedExisting) throw new NotFoundError("Rename File Not Found Error"); + + return file; + } + + deleteFile = async(userID: string, fileID: string) => { + + let bucket = new mongoose.mongo.GridFSBucket(conn.db, { + chunkSizeBytes: 1024 * 255, + }); + + const file = await dbUtilsFile.getFileInfo(fileID, userID); + + if (!file) throw new NotFoundError("Delete File Not Found Error"); + + if (file.metadata.thumbnailID) { + + await Thumbnail.deleteOne({_id: file.metadata.thumbnailID}); + } + + if (file.metadata.isVideo && file.metadata.transcoded) { + try { + await bucket.delete(ObjectID(file.metadata.transcodedID)); + } catch (e) { + console.log("Could Not Find Transcoded Video"); + } + } + + await bucket.delete(ObjectID(fileID)); + } +} + +export default MongoFileService; \ No newline at end of file diff --git a/backend/services/FolderService/index.js b/backend/services/FolderService/index.js index a22bfd3..87ad37b 100644 --- a/backend/services/FolderService/index.js +++ b/backend/services/FolderService/index.js @@ -1,13 +1,13 @@ const Folder = require("../../models/folder"); -const InternalServerError = require("../../../src/utils/InternalServerError"); -const NotFoundError = require("../../../src/utils/NotFoundError"); +const InternalServerError = require("../../utils/InternalServerError"); +const NotFoundError = require("../../utils/NotFoundError"); const UtilsFile = require("../../db/utils/fileUtils"); const ObjectID = require('mongodb').ObjectID const UtilsFolder = require("../../db/utils/folderUtils"); const mongoose = require("../../db/mongoose") const conn = mongoose.connection; const Thumbnail = require("../../models/thumbnail"); -const sortBySwitch = require("../../../src/utils/sortBySwitchFolder") +const sortBySwitch = require("../../utils/sortBySwitchFolder"); const utilsFile = new UtilsFile(); const utilsFolder = new UtilsFolder(); diff --git a/backend/services/UserService/index.js b/backend/services/UserService/index.js index b1cc6c6..b18ed44 100644 --- a/backend/services/UserService/index.js +++ b/backend/services/UserService/index.js @@ -1,9 +1,9 @@ const User = require("../../models/user"); const bcrypt = require("bcrypt"); const crypto = require("crypto"); -const NotFoundError = require("../../../src/utils/NotFoundError"); -const InternalServerError = require("../../../src/utils/InternalServerError"); -const NotAuthorizedError = require("../../../src/utils/NotAuthorizedError"); +const NotFoundError = require("../../utils/NotFoundError"); +const InternalServerError = require("../../utils/InternalServerError"); +const NotAuthorizedError = require("../../utils/NotAuthorizedError"); const UserService = function() { diff --git a/backend/utils/InternalServerError.js b/backend/utils/InternalServerError.js new file mode 100644 index 0000000..5556ea5 --- /dev/null +++ b/backend/utils/InternalServerError.js @@ -0,0 +1,10 @@ +class InternalServerError extends Error { + + constructor(args) { + super(args); + + this.code = 500; + } +} + +module.exports = InternalServerError; \ No newline at end of file diff --git a/backend/utils/NotAuthorizedError.js b/backend/utils/NotAuthorizedError.js new file mode 100644 index 0000000..d28fd6e --- /dev/null +++ b/backend/utils/NotAuthorizedError.js @@ -0,0 +1,10 @@ +class NotAuthorizedError extends Error { + + constructor(args) { + super(args); + + this.code = 401; + } +} + +module.exports = NotAuthorizedError; \ No newline at end of file diff --git a/backend/utils/NotFoundError.js b/backend/utils/NotFoundError.js new file mode 100644 index 0000000..128205f --- /dev/null +++ b/backend/utils/NotFoundError.js @@ -0,0 +1,10 @@ +class NotFoundError extends Error { + + constructor(args) { + super(args); + + this.code = 404; + } +} + +module.exports = NotFoundError; \ No newline at end of file diff --git a/backend/utils/createError.js b/backend/utils/createError.js new file mode 100644 index 0000000..6e9efc1 --- /dev/null +++ b/backend/utils/createError.js @@ -0,0 +1,12 @@ +const createError = (message, code, exception) => { + + let error = new Error(message); + error.message = message + error.code = code + error.exception = exception + + throw error; + +} + +module.exports = createError; \ No newline at end of file diff --git a/backend/utils/createQuery.js b/backend/utils/createQuery.js new file mode 100644 index 0000000..c4f6751 --- /dev/null +++ b/backend/utils/createQuery.js @@ -0,0 +1,41 @@ +const createQuery = (owner, parent,sortBy, startAt, startAtDate,searchQuery, startAtName) => { + + let query = {"metadata.owner": owner} + + if (searchQuery !== "") { + + searchQuery = new RegExp(searchQuery, 'i') + + query = {...query, filename: searchQuery} + + } else { + + query = {...query, "metadata.parent": parent} + } + + if (startAt) { + + if (sortBy === "date_desc" || sortBy === "DEFAULT") { + + query = {...query, "uploadDate": {$lt: new Date(startAtDate)}} + + } else if (sortBy === "date_asc") { + + query = {...query, "uploadDate": {$gt: new Date(startAtDate)}} + + } else if (sortBy === "alp_desc") { + + query = {...query, "filename": {$lt: startAtName}} + + } else { + + query = {...query, "filename": {$gt: startAtName}} + } + } + + + return query; + +} + +module.exports = createQuery \ No newline at end of file diff --git a/backend/utils/imageChecker.js b/backend/utils/imageChecker.js new file mode 100644 index 0000000..2df835e --- /dev/null +++ b/backend/utils/imageChecker.js @@ -0,0 +1,31 @@ +const videoExtList = [ + "jpeg", + "jpg", + "png", + "gif", + "svg", + "tiff", + "bmp" +] + +const videoChecker = (filename) => { + + if (filename.length < 1 || !filename.includes(".")) { + + return false; + } + + const extSplit = filename.split("."); + + if (extSplit < 1) { + + return false; + } + + const ext = extSplit[extSplit.length - 1]; + + return videoExtList.includes(ext.toLowerCase()); + +} + +module.exports = videoChecker; \ No newline at end of file diff --git a/backend/utils/mobileCheck.js b/backend/utils/mobileCheck.js new file mode 100644 index 0000000..67876d7 --- /dev/null +++ b/backend/utils/mobileCheck.js @@ -0,0 +1,6 @@ +const mobilecheck = () => { + var check = false; + (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera); + return check; + }; +export default mobilecheck; diff --git a/backend/utils/sortBySwitch.js b/backend/utils/sortBySwitch.js new file mode 100644 index 0000000..d0c43c3 --- /dev/null +++ b/backend/utils/sortBySwitch.js @@ -0,0 +1,15 @@ +const sortBySwitch = (sortBy) => { + switch(sortBy) { + + case "alp_asc": + return {filename: 1} + case "alp_desc": + return {filename: -1} + case "date_asc": + return {uploadDate: 1} + default: + return {uploadDate: -1} + } +} + +module.exports = sortBySwitch; \ No newline at end of file diff --git a/backend/utils/sortBySwitchFolder.js b/backend/utils/sortBySwitchFolder.js new file mode 100644 index 0000000..314397e --- /dev/null +++ b/backend/utils/sortBySwitchFolder.js @@ -0,0 +1,15 @@ +const sortBySwitch = (sortBy) => { + switch(sortBy) { + + case "alp_asc": + return {name: 1} + case "alp_desc": + return {name: -1} + case "date_asc": + return {createdAt: 1} + default: + return {createdAt: -1} + } +} + +module.exports = sortBySwitch; \ No newline at end of file diff --git a/backend/utils/videoChecker.js b/backend/utils/videoChecker.js new file mode 100644 index 0000000..e3c31f6 --- /dev/null +++ b/backend/utils/videoChecker.js @@ -0,0 +1,57 @@ +const videoExtList = [ + "3g2", + "3gp", + "aaf", + "asf", + "avchd", + "avi", + "drc", + "flv", + "m2v", + "m4p", + "m4v", + "mkv", + "mng", + "mov", + "mp2", + "mp4", + "mpe", + "mpeg", + "mpg", + "mpv", + "mxf", + "nsv", + "ogg", + "ogv", + "qt", + "rm", + "rmvb", + "roq", + "svi", + "vob", + "webm", + "wmv", + "yuv" +] + +const videoChecker = (filename) => { + + if (filename.length < 1 || !filename.includes(".")) { + + return false; + } + + const extSplit = filename.split("."); + + if (extSplit < 1) { + + return false; + } + + const ext = extSplit[extSplit.length - 1]; + + return videoExtList.includes(ext.toLowerCase()); + +} + +module.exports = videoChecker; \ No newline at end of file diff --git a/dist/controllers/file.js b/dist/controllers/file.js new file mode 100644 index 0000000..e8b5ae4 --- /dev/null +++ b/dist/controllers/file.js @@ -0,0 +1,420 @@ +"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 FileService = require("../services/FileService") +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(); +class FileController { + // fileService: ; + constructor() { + this.getThumbnail = (req, res) => __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const user = req.user; + const id = req.params.id; + const decryptedThumbnail = yield fileService.getThumbnail(user, id); + res.send(decryptedThumbnail); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + // async getFullThumbnail(req: RequestType, res: Response) { + // if (!req.user) { + // return; + // } + // try { + // const user = req.user; + // const fileID = req.params.id; + // await fileService.getFullThumbnail(user, fileID, res); + // } catch (e) { + // const code = e.code || 500; + // console.log(e.message, e.exception) + // return res.status(code).send(); + // } + // } + // async uploadFile(req: RequestType, res: Response) { + // if (!req.user) { + // return + // } + // try { + // const user = req.user; + // const busboy = req.busboy; + // req.pipe(busboy); + // const file = await fileService.upload(user, busboy, req); + // res.send(file); + // console.log("file uploaded"); + // } catch (e) { + // const code = e.code || 500; + // console.log(e.message, e.exception) + // return res.status(code).send(); + // } + // } + // async getPublicDownload(req: RequestType, res: Response) { + // try { + // const ID = req.params.id; + // const tempToken = req.params.tempToken; + // await fileService.publicDownload(ID, tempToken, res); + // } catch (e) { + // const code = e.code || 500; + // const message = e.message || e; + // console.log(message, e); + // res.status(code).send(); + // } + // } + removeLink(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const id = req.params.id; + const userID = req.user._id; + yield fileService.removeLink(userID, id); + res.send(); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + makePublic(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const fileID = req.params.id; + const user = req.user; + const token = yield fileService.makePublic(user, fileID); + res.send(token); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + getPublicInfo(req, res) { + return __awaiter(this, void 0, void 0, function* () { + try { + const id = req.params.id; + const tempToken = req.params.tempToken; + const file = yield fileService.getPublicInfo(id, tempToken); + res.send(file); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + makeOneTimePublic(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const id = req.params.id; + const userID = req.user._id; + const token = yield fileService.makeOneTimePublic(userID, id); + res.send(token); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + getFileInfo(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const fileID = req.params.id; + const userID = req.user._id; + const file = yield fileService.getFileInfo(userID, fileID); + res.send(file); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + getQuickList(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const userID = req.user._id; + const quickList = yield fileService.getQuickList(userID); + res.send(quickList); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + getList(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const query = req.query; + const userID = req.user._id; + const fileList = yield fileService.getList(userID, query); + res.send(fileList); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + getDownloadToken(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const user = req.user; + const tempToken = yield fileService.getDownloadToken(user); + res.send({ tempToken }); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + getDownloadTokenVideo(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const user = req.user; + const cookie = req.headers.uuid; + const tempToken = yield fileService.getDownloadTokenVideo(user, cookie); + res.send({ tempToken }); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + removeTempToken(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const user = req.user; + const tempToken = req.params.tempToken; + yield fileService.removeTempToken(user, tempToken); + res.send(); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + // async transcodeVideo(req: RequestType, res: Response) { + // if (!req.user) { + // return; + // } + // try { + // console.log("transcode request", req.body.file._id) + // const user = req.user; + // const body = req.body; + // await fileService.transcodeVideo(user, body); + // res.send("Finished"); + // } catch (e) { + // const code = e.code || 500; + // console.log(e.message, e.exception) + // return res.status(code).send(); + // } + // } + // async removeTranscodeVideo(req: RequestType, res: Response) { + // if (!req.user) { + // return; + // } + // try { + // const fileID = req.body.id; + // const userID = req.user._id; + // await fileService.removeTranscodeVideo(userID, fileID); + // res.send(); + // } catch (e) { + // const code = e.code || 500; + // console.log(e); + // res.status(code).send() + // } + // } + // async streamTranscodedVideo(req: RequestType, res: Response) { + // if (!req.auth || !req.user) { + // return; + // } + // try { + // console.log("stream request transcoded", req.params.id) + // const fileID = req.params.id; + // const userID = req.user._id; + // const headers = req.headers; + // await fileService.streamTranscodedVideo(userID, fileID, headers, res); + // } catch (e) { + // const code = e.code || 500; + // const message = e.message || e; + // console.log(message, e); + // res.status(code).send(); + // } + // } + // async streamVideo(req: RequestType, res: Response) { + // if (!req.auth || !req.user) { + // return; + // } + // try { + // const user = req.user; + // const fileID = req.params.id; + // const headers = req.headers; + // console.log("stream request", req.params.id) + // await fileService.streamVideo(user, fileID, headers, res); + // } catch (e) { + // const code = e.code || 500; + // const message = e.message || e; + // console.log(message, e); + // res.status(code).send(); + // } + // } + downloadFile(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.auth || !req.user) { + return; + } + try { + console.log("download request"); + const user = req.user; + const fileID = req.params.id; + //await fileService.downloadFile(user, fileID, res); + yield mongoService.downloadFile(user, fileID, res); + } + catch (e) { + const code = e.code || 500; + const message = e.message || e; + console.log(message, e); + res.status(code).send(); + } + }); + } + getSuggestedList(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const userID = req.user._id; + let searchQuery = req.query.search || ""; + const { fileList, folderList } = yield fileService.getSuggestedList(userID, searchQuery); + return res.send({ folderList, fileList }); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + renameFile(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const fileID = req.body.id; + const title = req.body.title; + const userID = req.user._id; + yield fileService.renameFile(userID, fileID, title); + res.send(); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + moveFile(req, res) { + return __awaiter(this, void 0, void 0, function* () { + console.log("move request"); + if (!req.user) { + return; + } + try { + const fileID = req.body.id; + const userID = req.user._id; + const parentID = req.body.parent; + console.log(fileID, userID, parentID); + yield fileService.moveFile(userID, fileID, parentID); + res.send(); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } + deleteFile(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const userID = req.user._id; + const fileID = req.body.id; + yield fileService.deleteFile(userID, fileID); + res.send(); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(); + } + }); + } +} +exports.default = FileController; diff --git a/dist/controllers/folder.js b/dist/controllers/folder.js new file mode 100644 index 0000000..73aed5a --- /dev/null +++ b/dist/controllers/folder.js @@ -0,0 +1,162 @@ +"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()); + }); +}; +const FolderService = require("../services/FolderService"); +const folderService = new FolderService(); +class FolderController { + constructor() { + } + uploadFolder(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const data = req.body; + const folder = yield folderService.uploadFolder(data); + res.send(folder); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(e); + } + }); + } + deleteFolder(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const userID = req.user._id; + const folderID = req.body.id; + const parentList = req.body.parentList; + yield folderService.deleteFolder(userID, folderID, parentList); + res.send(); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(e); + } + }); + } + deleteAll(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const userID = req.user._id; + yield folderService.deleteAll(userID); + res.send(); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(e); + } + }); + } + getInfo(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const userID = req.user._id; + const folderID = req.params.id; + const folder = yield folderService.getFolderInfo(userID, folderID); + res.send(folder); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(e); + } + }); + } + getSubfolderList(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const userID = req.user._id; + const folderID = req.query.id; + const { folderIDList, folderNameList } = yield folderService.getFolderSublist(userID, folderID); + res.send({ folderIDList, folderNameList }); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(e); + } + }); + } + getFolderList(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const userID = req.user._id; + const query = req.query; + const folderList = yield folderService.getFolderList(userID, query); + res.send(folderList); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(e); + } + }); + } + moveFolder(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const userID = req.user._id; + const folderID = req.body.id; + const parent = req.body.parent; + yield folderService.moveFolder(userID, folderID, parent); + res.send(); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(e); + } + }); + } + renameFolder(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const userID = req.user._id; + const folderID = req.body.id; + const title = req.body.title; + yield folderService.renameFolder(userID, folderID, title); + res.send(); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(e); + } + }); + } +} +module.exports = FolderController; diff --git a/dist/controllers/storage.js b/dist/controllers/storage.js new file mode 100644 index 0000000..b1acae1 --- /dev/null +++ b/dist/controllers/storage.js @@ -0,0 +1,32 @@ +"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()); + }); +}; +const env = require("../enviroment/env"); +const disk = require('diskusage'); +class StorageController { + constructor() { + } + getStorageInfo(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const info = yield disk.check(env.root); + res.send(info); + } + catch (e) { + console.log(e); + res.status(500).send(e); + } + }); + } +} +module.exports = StorageController; diff --git a/dist/controllers/user.js b/dist/controllers/user.js new file mode 100644 index 0000000..34aeeff --- /dev/null +++ b/dist/controllers/user.js @@ -0,0 +1,121 @@ +"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()); + }); +}; +const env = require("../enviroment/env"); +const UserService = require("../services/UserService"); +const UserProvider = new UserService(); +class UserController { + constructor() { + } + getUser(req, res) { + return __awaiter(this, void 0, void 0, function* () { + try { + const user = req.user; + user.tokens = undefined; + user.tempTokens = undefined; + user.password = undefined; + user.privateKey = undefined; + user.publicKey = undefined; + res.send(user); + } + catch (e) { + res.status(500).send(e); + } + }); + } + login(req, res) { + return __awaiter(this, void 0, void 0, function* () { + try { + const body = req.body; + const { user, token } = yield UserProvider.login(body); + user.tokens = undefined; + user.tempTokens = undefined; + user.password = undefined; + user.privateKey = undefined; + user.publicKey = undefined; + res.status(200).send({ user, token }); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(e); + } + }); + } + logout(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const user = req.user; + const token = req.encryptedToken; + yield UserProvider.logout(user, token); + res.send(); + } + catch (e) { + res.status(500).send(e); + } + }); + } + logoutAll(req, res) { + return __awaiter(this, void 0, void 0, function* () { + try { + const user = req.user; + yield UserProvider.logoutAll(user); + res.send(); + } + catch (e) { + res.status(500).send(e); + } + }); + } + createUser(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (env.createAcctBlocked) { + return yield res.status(401).send(); + } + try { + const { user, token } = yield UserProvider.create(req.body); + user.tokens = undefined; + user.tempTokens = undefined; + user.password = undefined; + user.privateKey = undefined; + user.publicKey = undefined; + res.status(201).send({ user, token }); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(e); + } + }); + } + changePassword(req, res) { + return __awaiter(this, void 0, void 0, function* () { + if (!req.user) { + return; + } + try { + const user = req.user; + const oldPassword = req.body.oldPassword; + const newPassword = req.body.newPassword; + const newToken = yield UserProvider.changePassword(user, oldPassword, newPassword); + res.send(newToken); + } + catch (e) { + const code = e.code || 500; + console.log(e); + res.status(code).send(e); + } + }); + } +} +module.exports = UserController; diff --git a/dist/db/mongoose.js b/dist/db/mongoose.js new file mode 100644 index 0000000..63e99c8 --- /dev/null +++ b/dist/db/mongoose.js @@ -0,0 +1,9 @@ +"use strict"; +const mongoose = require("mongoose"); +const env = require("../enviroment/env"); +mongoose.connect(env.mongoURL, { + useNewUrlParser: true, + useCreateIndex: true, + useUnifiedTopology: true, +}); +module.exports = mongoose; diff --git a/dist/db/mongooseServerUtils.js b/dist/db/mongooseServerUtils.js new file mode 100644 index 0000000..14e286d --- /dev/null +++ b/dist/db/mongooseServerUtils.js @@ -0,0 +1,11 @@ +"use strict"; +const mongoose = require("mongoose"); +const env = require("../enviroment/env"); +mongoose.connect(env.mongoURL, { + useNewUrlParser: true, + useCreateIndex: true, + useUnifiedTopology: true, + socketTimeoutMS: 30000000, + keepAlive: true, +}); +module.exports = mongoose; diff --git a/dist/db/utils/fileUtils/index.js b/dist/db/utils/fileUtils/index.js new file mode 100644 index 0000000..1942447 --- /dev/null +++ b/dist/db/utils/fileUtils/index.js @@ -0,0 +1,117 @@ +"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()); + }); +}; +const mongoose = require("../../mongoose"); +const conn = mongoose.connection; +const ObjectID = require('mongodb').ObjectID; +const DbUtil = function () { + this.getPublicFile = (fileID) => __awaiter(this, void 0, void 0, function* () { + let file = yield conn.db.collection("fs.files") + .findOne({ "_id": ObjectID(fileID) }); + return file; + }); + this.removeOneTimePublicLink = (fileID) => __awaiter(this, void 0, void 0, function* () { + const file = yield conn.db.collection("fs.files") + .findOneAndUpdate({ "_id": ObjectID(fileID) }, { + "$unset": { "metadata.linkType": "", "metadata.link": "" } + }); + return file; + }); + this.removeLink = (fileID, userID) => __awaiter(this, void 0, void 0, function* () { + const file = yield conn.db.collection("fs.files") + .findOneAndUpdate({ "_id": ObjectID(fileID), + "metadata.owner": userID }, { "$unset": { "metadata.linkType": "", "metadata.link": "" } }); + return file; + }); + this.makePublic = (fileID, userID, token) => __awaiter(this, void 0, void 0, function* () { + const file = yield conn.db.collection("fs.files") + .findOneAndUpdate({ "_id": ObjectID(fileID), + "metadata.owner": userID }, { "$set": { "metadata.linkType": "public", "metadata.link": token } }); + return file; + }); + this.getPublicInfo = (fileID, tempToken) => __awaiter(this, void 0, void 0, function* () { + const file = yield conn.db.collection("fs.files") + .findOne({ "_id": ObjectID(fileID), "metadata.link": tempToken }); + return file; + }); + this.makeOneTimePublic = (fileID, userID, token) => __awaiter(this, void 0, void 0, function* () { + const file = yield conn.db.collection("fs.files") + .findOneAndUpdate({ "_id": ObjectID(fileID), + "metadata.owner": userID }, { "$set": { "metadata.linkType": "one", "metadata.link": token } }); + return file; + }); + this.getFileInfo = (fileID, userID) => __awaiter(this, void 0, void 0, function* () { + const file = yield conn.db.collection("fs.files") + .findOne({ "metadata.owner": userID, "_id": ObjectID(fileID) }); + return file; + }); + this.getQuickList = (userID) => __awaiter(this, void 0, void 0, function* () { + const fileList = yield conn.db.collection("fs.files") + .find({ "metadata.owner": userID }) + .sort({ uploadDate: -1 }) + .limit(10) + .toArray(); + return fileList; + }); + this.getList = (queryObj, sortBy, limit) => __awaiter(this, void 0, void 0, function* () { + const fileList = yield conn.db.collection("fs.files") + .find(queryObj) + .sort(sortBy) + .limit(limit) + .toArray(); + return fileList; + }); + this.removeTempToken = (user, tempToken) => __awaiter(this, void 0, void 0, function* () { + user.tempTokens = user.tempTokens.filter((filterToken) => { + return filterToken.token !== tempToken; + }); + return user; + }); + this.removeTranscodeVideo = (fileID, userID) => __awaiter(this, void 0, void 0, function* () { + const file = yield conn.db.collection("fs.files") + .findOneAndUpdate({ "_id": ObjectID(fileID), "metadata.owner": userID }, { "$unset": { "metadata.transcoded": "", "metadata.transcodedIV": "", + "metadata.transcoded_size": "", "metadata.transcodedID": "" } }); + return file; + }); + this.getFileSearchList = (userID, searchQuery) => __awaiter(this, void 0, void 0, function* () { + const fileList = yield conn.db.collection("fs.files") + .find({ "metadata.owner": userID, "filename": searchQuery }) + .limit(10) + .toArray(); + return fileList; + }); + this.renameFile = (fileID, userID, title) => __awaiter(this, void 0, void 0, function* () { + const file = yield conn.db.collection("fs.files") + .findOneAndUpdate({ "_id": ObjectID(fileID), + "metadata.owner": userID }, { "$set": { "filename": title } }); + return file; + }); + this.moveFile = (fileID, userID, parent, parentList) => __awaiter(this, void 0, void 0, function* () { + const file = yield conn.db.collection("fs.files") + .findOneAndUpdate({ "_id": ObjectID(fileID), + "metadata.owner": userID }, { "$set": { "metadata.parent": parent, "metadata.parentList": parentList } }); + return file; + }); + this.getFileListByParent = (userID, parentListString) => __awaiter(this, void 0, void 0, function* () { + const fileList = yield conn.db.collection("fs.files") + .find({ "metadata.owner": userID, + "metadata.parentList": { $regex: `.*${parentListString}.*` } }).toArray(); + return fileList; + }); + this.getFileListByOwner = (userID) => __awaiter(this, void 0, void 0, function* () { + const fileList = yield conn.db.collection("fs.files") + .find({ "metadata.owner": userID }).toArray(); + return fileList; + }); + this.removeChunksByID = (fileID) => __awaiter(this, void 0, void 0, function* () { + yield conn.db.collection("fs.chunks").deleteMany({ files_id: fileID }); + }); +}; +module.exports = DbUtil; diff --git a/dist/db/utils/folderUtils/index.js b/dist/db/utils/folderUtils/index.js new file mode 100644 index 0000000..f4c3ea4 --- /dev/null +++ b/dist/db/utils/folderUtils/index.js @@ -0,0 +1,47 @@ +"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()); + }); +}; +const Folder = require("../../../models/folder"); +const ObjectID = require('mongodb').ObjectID; +const DbUtil = function () { + this.getFolderSearchList = (userID, searchQuery) => __awaiter(this, void 0, void 0, function* () { + const folderList = yield Folder.find({ "owner": userID, "name": searchQuery }).limit(10); + return folderList; + }); + this.getFolderInfo = (folderID, userID) => __awaiter(this, void 0, void 0, function* () { + const folder = yield Folder.findOne({ "owner": userID, "_id": ObjectID(folderID) }); + return folder; + }); + this.getFolderListByParent = (userID, parent, sortBy) => __awaiter(this, void 0, void 0, function* () { + const folderList = yield Folder.find({ "owner": userID, "parent": parent }) + .sort(sortBy); + return folderList; + }); + this.getFolderListBySearch = (userID, searchQuery, sortBy) => __awaiter(this, void 0, void 0, function* () { + const folderList = yield Folder.find({ "name": searchQuery, "owner": userID }) + .sort(sortBy); + return folderList; + }); + this.moveFolder = (folderID, userID, parent, parentList) => __awaiter(this, void 0, void 0, function* () { + const folder = yield Folder.findOneAndUpdate({ "_id": ObjectID(folderID), + "owner": userID }, { "$set": { "parent": parent, "parentList": parentList } }); + return folder; + }); + this.renameFolder = (folderID, userID, title) => __awaiter(this, void 0, void 0, function* () { + const folder = yield Folder.findOneAndUpdate({ "_id": ObjectID(folderID), + "owner": userID }, { "$set": { "name": title } }); + return folder; + }); + this.findAllFoldersByParent = (parentID, userID) => __awaiter(this, void 0, void 0, function* () { + const folderList = yield Folder.find({ "parentList": parentID, "owner": userID }); + return folderList; + }); +}; +module.exports = DbUtil; diff --git a/dist/enviroment/env.js b/dist/enviroment/env.js new file mode 100644 index 0000000..19007e7 --- /dev/null +++ b/dist/enviroment/env.js @@ -0,0 +1,10 @@ +"use strict"; +module.exports = { + key: process.env.KEY, + newKey: process.env.NEW_KEY, + password: process.env.PASSWORD, + createAcctBlocked: process.env.BLOCK_CREATE_ACCOUNT, + root: process.env.ROOT, + url: process.env.URL, + mongoURL: process.env.MONGODB_URL +}; diff --git a/dist/express-routers/file.js b/dist/express-routers/file.js new file mode 100644 index 0000000..89692aa --- /dev/null +++ b/dist/express-routers/file.js @@ -0,0 +1,36 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = require("express"); +const router = express_1.Router(); +const auth = require("../middleware/auth"); +const tempAuth = require("../middleware/tempAuth"); +const tempAuthVideo = require("../middleware/tempAuthVideo"); +const file_1 = __importDefault(require("../controllers/file")); +const fileController = new file_1.default(); +//router.post("/file-service/upload", auth, fileController.uploadFile); +//router.post("/file-service/transcode-video", auth, fileController.transcodeVideo); +router.get("/file-service/thumbnail/:id", auth, fileController.getThumbnail); +//router.get("/file-service/full-thumbnail/:id", auth, fileController.getFullThumbnail); +//router.get("/file-service/public/download/:id/:tempToken", fileController.getPublicDownload); +router.get("/file-service/public/info/:id/:tempToken", fileController.getPublicInfo); +router.get("/file-service/info/:id", auth, fileController.getFileInfo); +router.get("/file-service/quick-list", auth, fileController.getQuickList); +router.get("/file-service/list", auth, fileController.getList); +router.get("/file-service/download/get-token", auth, fileController.getDownloadToken); +router.get("/file-service/download/get-token-video", auth, fileController.getDownloadTokenVideo); +//router.get("/file-service/stream-video-transcoded/:id/:tempToken/:uuid", tempAuthVideo, fileController.streamTranscodedVideo); +//router.get("/file-service/stream-video/:id/:tempToken/:uuid", tempAuthVideo, fileController.streamVideo); +router.get("/file-service/download/:id/:tempToken", tempAuth, fileController.downloadFile); +router.get("/file-service/suggested-list", auth, fileController.getSuggestedList); +router.patch("/file-service/make-public/:id", auth, fileController.makePublic); +router.patch("/file-service/make-one/:id", auth, fileController.makeOneTimePublic); +router.patch("/file-service/rename", auth, fileController.renameFile); +router.patch("/file-service/move", auth, fileController.moveFile); +router.delete("/file-service/remove-link/:id", auth, fileController.removeLink); +router.delete("/file-service/remove/token-video/:tempToken", auth, fileController.removeTempToken); +//router.delete("/file-service/transcode-video/remove", auth, fileController.removeTranscodeVideo); +router.delete("/file-service/remove", auth, fileController.deleteFile); +module.exports = router; diff --git a/dist/express-routers/folder.js b/dist/express-routers/folder.js new file mode 100644 index 0000000..17d2f1c --- /dev/null +++ b/dist/express-routers/folder.js @@ -0,0 +1,16 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = require("express"); +const router = express_1.Router(); +const auth = require("../middleware/auth"); +const FolderController = require("../controllers/folder"); +const folderController = new FolderController(); +router.post("/folder-service/upload", auth, folderController.uploadFolder); +router.delete("/folder-service/remove", auth, folderController.deleteFolder); +router.delete("/folder-service/remove-all", auth, folderController.deleteAll); +router.get("/folder-service/info/:id", auth, folderController.getInfo); +router.get("/folder-service/subfolder-list", auth, folderController.getSubfolderList); +router.get("/folder-service/list", auth, folderController.getFolderList); +router.patch("/folder-service/rename", auth, folderController.renameFolder); +router.patch("/folder-service/move", auth, folderController.moveFolder); +module.exports = router; diff --git a/dist/express-routers/storage.js b/dist/express-routers/storage.js new file mode 100644 index 0000000..3436a64 --- /dev/null +++ b/dist/express-routers/storage.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = require("express"); +const router = express_1.Router(); +const auth = require("../middleware/auth"); +const StorageController = require("../controllers/storage"); +const storageController = new StorageController(); +router.get("/storage-service/info", auth, storageController.getStorageInfo); +module.exports = router; diff --git a/dist/express-routers/user.js b/dist/express-routers/user.js new file mode 100644 index 0000000..4a8a393 --- /dev/null +++ b/dist/express-routers/user.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = require("express"); +const router = express_1.Router(); +const auth = require("../middleware/auth"); +const UserController = require("../controllers/user"); +const userController = new UserController(); +router.get("/user-service/user", auth, userController.getUser); +router.post("/user-service/login", userController.login); +router.post("/user-service/logout", auth, userController.logout); +router.post("/user-service/logout-all", auth, userController.logoutAll); +router.post("/user-service/create", userController.createUser); +router.post("/user-service/change-password", auth, userController.changePassword); +module.exports = router; diff --git a/dist/key/getKey.js b/dist/key/getKey.js new file mode 100644 index 0000000..87cdd47 --- /dev/null +++ b/dist/key/getKey.js @@ -0,0 +1,30 @@ +"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()); + }); +}; +const prompt = require('password-prompt'); +const env = require("../enviroment/env"); +const crypto = require("crypto"); +const getKey = () => __awaiter(void 0, void 0, void 0, function* () { + if (process.env.KEY) { + // For Docker + env.key = process.env.KEY; + } + else if (process.env.NODE_ENV) { + let password = yield prompt("Enter Server Encryption Password: ", { method: "hide" }); + password = crypto.createHash("md5").update(password).digest("hex"); + env.key = password; + } + else { + let password = "1234"; + password = crypto.createHash("md5").update(password).digest("hex"); + env.key = password; + } +}); +module.exports = getKey; diff --git a/dist/middleware/auth.js b/dist/middleware/auth.js new file mode 100644 index 0000000..e00bb45 --- /dev/null +++ b/dist/middleware/auth.js @@ -0,0 +1,45 @@ +"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()); + }); +}; +const jwt = require("jsonwebtoken"); +const User = require("../models/user"); +const env = require("../enviroment/env"); +const auth = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { + try { + const token = req.header("Authorization").replace("Bearer ", ""); + const decoded = yield jwt.verify(token, env.password); + const iv = decoded.iv; + const user = yield User.findOne({ _id: decoded._id }); + const encrpytionKey = user.getEncryptionKey(); + const encryptedToken = user.encryptToken(token, encrpytionKey, iv); + let tokenFound = false; + for (let i = 0; i < user.tokens.length; i++) { + const currentToken = user.tokens[i].token; + if (currentToken === encryptedToken) { + tokenFound = true; + break; + } + } + if (!user || !tokenFound) { + throw new Error("User not found"); + } + else { + req.token = token; + req.encryptedToken = encryptedToken; + req.user = user; + next(); + } + } + catch (e) { + console.log(e); + res.status(401).send({ error: "Error Authenticating" }); + } +}); +module.exports = auth; diff --git a/dist/middleware/tempAuth.js b/dist/middleware/tempAuth.js new file mode 100644 index 0000000..206a31b --- /dev/null +++ b/dist/middleware/tempAuth.js @@ -0,0 +1,49 @@ +"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()); + }); +}; +const jwt = require("jsonwebtoken"); +const User = require("../models/user"); +const env = require("../enviroment/env"); +const tempAuth = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { + try { + const token = req.params.tempToken; + const decoded = yield jwt.verify(token, env.password); + const iv = decoded.iv; + const user = yield User.findOne({ _id: decoded._id }); + const encrpytionKey = user.getEncryptionKey(); + const encryptedToken = user.encryptToken(token, encrpytionKey, iv); + let tokenFound = false; + for (let i = 0; i < user.tempTokens.length; i++) { + const currentToken = user.tempTokens[i].token; + if (currentToken === encryptedToken) { + tokenFound = true; + break; + } + } + if (!user || !tokenFound) { + throw new Error("User Not Found"); + } + else { + user.tempTokens = user.tempTokens.filter((filterToken) => { + return filterToken.token !== encryptedToken; + }); + yield user.save(); + req.user = user; + req.auth = true; + req.encryptedTempToken = encryptedToken; + next(); + } + } + catch (e) { + console.log(e); + res.status(401).send(); + } +}); +module.exports = tempAuth; diff --git a/dist/middleware/tempAuthVideo.js b/dist/middleware/tempAuthVideo.js new file mode 100644 index 0000000..5cb9f1f --- /dev/null +++ b/dist/middleware/tempAuthVideo.js @@ -0,0 +1,49 @@ +"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()); + }); +}; +const jwt = require("jsonwebtoken"); +const User = require("../models/user"); +const env = require("../enviroment/env"); +const tempAuthVideo = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { + try { + const token = req.params.tempToken; + const decoded = yield jwt.verify(token, env.password); + const iv = decoded.iv; + if (req.params.uuid !== decoded.cookie) { + throw new Error("Cookie mismatch"); + } + const user = yield User.findOne({ _id: decoded._id }); + const encrpytionKey = user.getEncryptionKey(); + const encryptedToken = user.encryptToken(token, encrpytionKey, iv); + let tokenFound = false; + for (let i = 0; i < user.tempTokens.length; i++) { + const currentToken = user.tempTokens[i].token; + if (currentToken === encryptedToken) { + tokenFound = true; + break; + } + } + if (!user || !tokenFound) { + throw new Error("User not found"); + } + else { + yield user.save(); + req.user = user; + req.auth = true; + req.encryptedTempToken = encryptedToken; + next(); + } + } + catch (e) { + console.log(e); + res.status(401).send(); + } +}); +module.exports = tempAuthVideo; diff --git a/dist/models/file.js b/dist/models/file.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/dist/models/file.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/models/folder.js b/dist/models/folder.js new file mode 100644 index 0000000..39a8948 --- /dev/null +++ b/dist/models/folder.js @@ -0,0 +1,24 @@ +"use strict"; +const mongoose = require("mongoose"); +const folderSchema = new mongoose.Schema({ + name: { + type: String, + required: true, + }, + parent: { + type: String, + required: true, + }, + owner: { + type: String, + required: true + }, + parentList: { + type: Array, + required: true + } +}, { + timestamps: true +}); +const Folder = mongoose.model("Folder", folderSchema); +module.exports = Folder; diff --git a/dist/models/thumbnail.js b/dist/models/thumbnail.js new file mode 100644 index 0000000..149680c --- /dev/null +++ b/dist/models/thumbnail.js @@ -0,0 +1,24 @@ +"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 thumbnailSchema = new mongoose_1.default.Schema({ + name: { + type: String, + required: true, + }, + owner: { + type: String, + required: true + }, + data: { + type: Buffer, + required: true + } +}, { + timestamps: true +}); +const Thumbnail = mongoose_1.default.model("Thumbnail", thumbnailSchema); +exports.default = Thumbnail; diff --git a/dist/models/user.js b/dist/models/user.js new file mode 100644 index 0000000..c7344e2 --- /dev/null +++ b/dist/models/user.js @@ -0,0 +1,224 @@ +"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 mongoose_1 = __importDefault(require("mongoose")); +const validator = require("validator"); +const crypto = require("crypto"); +const bcrypt = require("bcrypt"); +const jwt = require("jsonwebtoken"); +const env = require("../enviroment/env"); +const userSchema = new mongoose_1.default.Schema({ + name: { + type: String, + trim: true + }, + email: { + type: String, + required: true, + trim: true, + unique: true, + lowercase: true, + validate(value) { + if (!validator.isEmail(value)) { + throw new Error("Email is invalid"); + } + } + }, + password: { + type: String, + trim: true, + required: true, + validate(value) { + if (value.length < 6) { + throw new Error("Password Length Not Sufficent"); + } + } + }, + tokens: [{ + token: { + type: String, + required: true + } + }], + tempTokens: [{ + token: { + type: String, + required: true + } + }], + privateKey: { + type: String, + }, + publicKey: { + type: String, + } +}, { + timestamps: true +}); +// userSchema.virtual("files", { +// ref: "fs.files", +// localField: "_id" +// }) +userSchema.pre("save", function (next) { + return __awaiter(this, void 0, void 0, function* () { + const user = this; + if (user.isModified("password")) { + user.password = yield bcrypt.hash(user.password, 8); + } + next(); + }); +}); +userSchema.statics.findByCreds = (email, password) => __awaiter(void 0, void 0, void 0, function* () { + const user = yield User.findOne({ email }); + if (!user) { + throw new Error("User not found"); + } + const isMatch = yield bcrypt.compare(password, user.password); + if (!isMatch) { + console.log("incorrect password"); + throw new Error("Incorrect password"); + } + return user; +}); +userSchema.methods.toJSON = function () { + const user = this; + const userObject = user.toObject(); + delete userObject.password; + delete userObject.tokens; + delete userObject.tempTokens; + return userObject; +}; +userSchema.methods.generateAuthToken = function () { + return __awaiter(this, void 0, void 0, function* () { + const iv = crypto.randomBytes(16); + const user = this; + let token = jwt.sign({ _id: user._id.toString(), iv }, env.password); + const publicKey = user.publicKey; + const encryptionKey = user.getEncryptionKey(); + const encryptedToken = user.encryptToken(token, encryptionKey, iv); + user.tokens = user.tokens.concat({ token: encryptedToken }); + yield user.save(); + return token; + }); +}; +userSchema.methods.encryptToken = function (token, key, iv) { + iv = Buffer.from(iv, "hex"); + const TOKEN_CIPHER_KEY = crypto.createHash('sha256').update(key).digest(); + const cipher = crypto.createCipheriv('aes-256-cbc', TOKEN_CIPHER_KEY, iv); + let encryptedText = cipher.update(token); + encryptedText = Buffer.concat([encryptedText, cipher.final()]).toString("hex"); + return encryptedText; +}; +userSchema.methods.decryptToken = function (encryptedToken, key, iv) { + encryptedToken = Buffer.from(encryptedToken, "hex"); + iv = Buffer.from(iv, "hex"); + const TOKEN_CIPHER_KEY = crypto.createHash('sha256').update(key).digest(); + const decipher = crypto.createDecipheriv('aes-256-cbc', TOKEN_CIPHER_KEY, iv); + let tokenDecrypted = decipher.update(encryptedToken); + tokenDecrypted = Buffer.concat([tokenDecrypted, decipher.final()]).toString(); + return tokenDecrypted; +}; +userSchema.methods.generateEncryptionKeys = function () { + return __awaiter(this, void 0, void 0, function* () { + const user = this; + const userPassword = user.password; + const masterPassword = env.key; + const randomKey = crypto.randomBytes(32); + const iv = crypto.randomBytes(16); + const USER_CIPHER_KEY = crypto.createHash('sha256').update(userPassword).digest(); + const cipher = crypto.createCipheriv('aes-256-cbc', USER_CIPHER_KEY, iv); + let encryptedText = cipher.update(randomKey); + encryptedText = Buffer.concat([encryptedText, cipher.final()]); + const MASTER_CIPHER_KEY = crypto.createHash('sha256').update(masterPassword).digest(); + const masterCipher = crypto.createCipheriv('aes-256-cbc', MASTER_CIPHER_KEY, iv); + let masterEncryptedText = masterCipher.update(encryptedText); + masterEncryptedText = Buffer.concat([masterEncryptedText, masterCipher.final()]).toString("hex"); + user.privateKey = masterEncryptedText; + user.publicKey = iv.toString("hex"); + yield user.save(); + }); +}; +userSchema.methods.getEncryptionKey = function () { + const user = this; + const userPassword = user.password; + const masterEncryptedText = user.privateKey; + const masterPassword = env.key; + const iv = Buffer.from(user.publicKey, "hex"); + const USER_CIPHER_KEY = crypto.createHash('sha256').update(userPassword).digest(); + const MASTER_CIPHER_KEY = crypto.createHash('sha256').update(masterPassword).digest(); + const unhexMasterText = Buffer.from(masterEncryptedText, "hex"); + const masterDecipher = crypto.createDecipheriv('aes-256-cbc', MASTER_CIPHER_KEY, iv); + let masterDecrypted = masterDecipher.update(unhexMasterText); + masterDecrypted = Buffer.concat([masterDecrypted, masterDecipher.final()]); + let decipher = crypto.createDecipheriv('aes-256-cbc', USER_CIPHER_KEY, iv); + let decrypted = decipher.update(masterDecrypted); + decrypted = Buffer.concat([decrypted, decipher.final()]); + return decrypted; +}; +userSchema.methods.changeEncryptionKey = function (randomKey) { + return __awaiter(this, void 0, void 0, function* () { + const user = this; + const userPassword = user.password; + const masterPassword = env.key; + const iv = crypto.randomBytes(16); + const USER_CIPHER_KEY = crypto.createHash('sha256').update(userPassword).digest(); + const cipher = crypto.createCipheriv('aes-256-cbc', USER_CIPHER_KEY, iv); + let encryptedText = cipher.update(randomKey); + encryptedText = Buffer.concat([encryptedText, cipher.final()]); + const MASTER_CIPHER_KEY = crypto.createHash('sha256').update(masterPassword).digest(); + const masterCipher = crypto.createCipheriv('aes-256-cbc', MASTER_CIPHER_KEY, iv); + let masterEncryptedText = masterCipher.update(encryptedText); + masterEncryptedText = Buffer.concat([masterEncryptedText, masterCipher.final()]).toString("hex"); + user.privateKey = masterEncryptedText; + user.publicKey = iv.toString("hex"); + yield user.save(); + }); +}; +userSchema.methods.generateTempAuthToken = function () { + return __awaiter(this, void 0, void 0, function* () { + // const user = this; + // let token = jwt.sign({_id:user._id.toString()}, env.password); + // const publicKey = user.publicKey; + // const encryptionKey = user.getEncryptionKey(); + // const encryptedToken = user.encryptToken(token, encryptionKey, publicKey); + // user.tokens = user.tokens.concat({token: encryptedToken}); + // await user.save(); + // return token; + const iv = crypto.randomBytes(16); + const user = this; + const token = jwt.sign({ _id: user._id.toString(), iv }, env.password, { expiresIn: 2 }); + const publicKey = user.publicKey; + const encryptionKey = user.getEncryptionKey(); + const encryptedToken = user.encryptToken(token, encryptionKey, iv); + user.tempTokens = user.tempTokens.concat({ token: encryptedToken }); + yield user.save(); + return token; + }); +}; +userSchema.methods.generateTempAuthTokenVideo = function (cookie) { + return __awaiter(this, void 0, void 0, function* () { + const iv = crypto.randomBytes(16); + const user = this; + const token = jwt.sign({ _id: user._id.toString(), cookie, iv }, env.password, { expiresIn: "5h" }); + //const publicKey = user.publicKey; + const encryptionKey = user.getEncryptionKey(); + const encryptedToken = user.encryptToken(token, encryptionKey, iv); + //user.tempTokens = user.tempTokens.concat({token}); + user.tempTokens = user.tempTokens.concat({ token: encryptedToken }); + yield user.save(); + return token; + }); +}; +const User = mongoose_1.default.model("User", userSchema); +module.exports = User; diff --git a/dist/server/server.js b/dist/server/server.js new file mode 100644 index 0000000..cb5505f --- /dev/null +++ b/dist/server/server.js @@ -0,0 +1,52 @@ +"use strict"; +const express = require("express"); +const app = express(); +const path = require("path"); +const publicPath = path.join(__dirname, "..", "..", "public"); +const userRouter = require("../express-routers/user"); +const fileRouter = require("../express-routers/file"); +const folderRouter = require("../express-routers/folder"); +const storageRouter = require("../express-routers/storage"); +const bodyParser = require('body-parser'); +const https = require("https"); +const fs = require("fs"); +const helmet = require("helmet"); +const busboy = require("connect-busboy"); +const compression = require("compression"); +const http = require("http"); +let server; +let serverHttps; +if (process.env.NODE_ENV === 'production') { + const cert = fs.readFileSync("certificate.crt"); + const ca = fs.readFileSync("certificate.ca-bundle"); + const key = fs.readFileSync("certificate.key"); + const options = { + cert, + ca, + key + }; + serverHttps = https.createServer(options, app); +} +server = http.createServer(app); +require("../db/mongoose"); +app.use(helmet()); +app.use(compression()); +app.use(express.json()); +app.use(express.static(publicPath)); +app.use(bodyParser.json({ limit: "50mb" })); +app.use(bodyParser.urlencoded({ limit: "50mb", extended: true, parameterLimit: 50000 })); +app.use(busboy({ + highWaterMark: 2 * 1024 * 1024, +})); +app.use(userRouter, fileRouter, folderRouter, storageRouter); +const nodeMode = process.env.NODE_ENV ? "Production" : "Development/Testing"; +console.log("Node Enviroment Mode:", nodeMode); +app.get("*", (req, res) => { + res.sendFile(path.join(publicPath, "index.html")); +}); +if (process.env.NODE_ENV === 'production') { + module.exports = { server, serverHttps }; +} +else { + module.exports = server; +} diff --git a/dist/server/serverStart.js b/dist/server/serverStart.js new file mode 100644 index 0000000..ab1b73b --- /dev/null +++ b/dist/server/serverStart.js @@ -0,0 +1,36 @@ +"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()); + }); +}; +const getKey = require("../key/getKey"); +const serverStart = () => __awaiter(void 0, void 0, void 0, function* () { + yield getKey(); + if (process.env.NODE_ENV === 'production') { + const { server, serverHttps } = require("./server"); + server.listen(process.env.HTTP_PORT, process.env.URL, () => { + console.log("Http Server Running On Port:", process.env.HTTP_PORT); + }); + serverHttps.listen(process.env.HTTPS_PORT, function () { + console.log('Https Server Running On Port:', process.env.HTTPS_PORT); + }); + } + else if (process.env.NODE_ENV === 'production-no-ssl') { + const server = require("./server"); + server.listen(process.env.HTTP_PORT, process.env.URL, () => { + console.log("Http Server (No-SSL) Running On Port:", process.env.HTTP_PORT); + }); + } + else { + const server = require("./server"); + server.listen(process.env.HTTP_PORT, process.env.URL, () => { + console.log("Development Server Running On Port:", process.env.HTTP_PORT); + }); + } +}); +serverStart(); diff --git a/dist/services/ChunkService/MongoService.js b/dist/services/ChunkService/MongoService.js new file mode 100644 index 0000000..8b84ff7 --- /dev/null +++ b/dist/services/ChunkService/MongoService.js @@ -0,0 +1,60 @@ +"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("../../db/mongoose")); +const conn = mongoose_1.default.connection; +const env = require("../../enviroment/env"); +const DbUtilFolder = require("../../db/utils/folderUtils"); +const index_1 = __importDefault(require("../../db/utils/fileUtils/index")); +const crypto_1 = __importDefault(require("crypto")); +const ObjectID = require('mongodb').ObjectID; +const dbUtilsFile = new index_1.default(); +const dbUtilsFolder = new DbUtilFolder(); +class MongoService { + constructor() { + this.downloadFile = (user, fileID, res) => { + return new Promise((resolve, reject) => { + dbUtilsFile.getFileInfo(fileID, user._id).then((currentFile) => { + if (!currentFile) { + reject({ + code: 401, + message: "Download File Not Found Error", + exception: undefined + }); + } + else { + const password = user.getEncryptionKey(); + const bucket = new mongoose_1.default.mongo.GridFSBucket(conn.db); + const IV = currentFile.metadata.IV.buffer; + const readStream = bucket.openDownloadStream(ObjectID(fileID)); + readStream.on("error", (e) => { + reject({ + code: 500, + message: "File service download decipher error", + exception: e + }); + }); + const CIPHER_KEY = crypto_1.default.createHash('sha256').update(password).digest(); + const decipher = crypto_1.default.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(); + }); + } + }); + }); + }; + } +} +exports.default = MongoService; diff --git a/dist/services/FileService/index.js b/dist/services/FileService/index.js new file mode 100644 index 0000000..12da623 --- /dev/null +++ b/dist/services/FileService/index.js @@ -0,0 +1,668 @@ +"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 imageChecker = require("../../utils/imageChecker"); +const crypto_1 = __importDefault(require("crypto")); +const videoChecker = require("../../utils/videoChecker"); +const mongoose = require("../../db/mongoose"); +const conn = mongoose.connection; +const createThumbnail = require("./utils/createThumbnail"); +const Thumbnail = require("../../models/thumbnail"); +const ObjectID = require('mongodb').ObjectID; +const NotAuthorizedError = require("../../utils/NotAuthorizedError"); +const NotFoundError = require("../../utils/NotFoundError"); +const env = require("../../enviroment/env"); +const jwt = require("jsonwebtoken"); +const removeChunks = require("./utils/removeChunks"); +const User = require("../../models/user"); +const Folder = require("../../models/folder"); +const sortBySwitch = require("../../utils/sortBySwitch"); +const createQuery = require("../../utils/createQuery"); +const ffmpeg = require("fluent-ffmpeg"); +const temp = require("temp").track(); +const progress = require("progress-stream"); +const fs = require("fs"); +const DbUtilFile = require("../../db/utils/fileUtils"); +const DbUtilFolder = require("../../db/utils/folderUtils"); +const dbUtilsFile = new DbUtilFile(); +const dbUtilsFolder = new DbUtilFolder(); +const FileService = function () { + this.upload = (user, busboy, req) => { + return new Promise((resolve, reject) => { + const password = user.getEncryptionKey(); + let bucketStream; + 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); + cipher.on("error", (e) => __awaiter(this, void 0, void 0, function* () { + yield removeChunks(bucketStream); + reject({ + message: "File service upload cipher error", + exception: e, + code: 500 + }); + })); + const formData = new Map(); + busboy.on("error", (e) => __awaiter(this, void 0, void 0, function* () { + yield removeChunks(bucketStream); + reject({ + message: "File service upload busboy error", + exception: e, + code: 500 + }); + })); + busboy.on("file", (fieldname, file, filename) => __awaiter(this, void 0, void 0, function* () { + 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", (e) => __awaiter(this, void 0, void 0, function* () { + yield removeChunks(bucketStream); + reject({ + message: "Cannot upload file to database", + exception: e, + code: 500 + }); + })); + req.on("aborted", () => __awaiter(this, void 0, void 0, function* () { + console.log("Upload Request Cancelling..."); + yield removeChunks(bucketStream); + })); + file.pipe(cipher).pipe(bucketStream); + bucketStream.on("finish", (file) => __awaiter(this, void 0, void 0, function* () { + const imageCheck = imageChecker(filename); + if (file.length < 15728640 && imageCheck) { + let updatedFile = yield createThumbnail(file, filename, user); + resolve(updatedFile); + } + else { + resolve(file); + } + })); + })).on("field", (field, val) => { + formData.set(field, val); + }); + }); + }; + this.getThumbnail = (user, id) => __awaiter(this, void 0, void 0, function* () { + const password = user.getEncryptionKey(); + const thumbnail = yield Thumbnail.findById(id); + if (user._id.toString() !== thumbnail.owner) { + throw new NotAuthorizedError("Thumbnail Unauthorized Error"); + } + const iv = thumbnail.data.slice(0, 16); + const chunk = thumbnail.data.slice(16); + const CIPHER_KEY = crypto_1.default.createHash('sha256').update(password).digest(); + const decipher = crypto_1.default.createDecipheriv("aes256", CIPHER_KEY, iv); + const decryptedThumbnail = Buffer.concat([decipher.update(chunk), decipher.final()]); + //console.log("decry", decryptedThumbnail); + return decryptedThumbnail; + }); + this.getFullThumbnail = (user, fileID, res) => __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { + const userID = user._id; + dbUtilsFile.getFileInfo(fileID, userID).then((file) => __awaiter(this, void 0, void 0, function* () { + 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(ObjectID(fileID)); + readStream.on("error", (e) => { + reject({ + code: 500, + message: "File service Full Thumbnail stream error", + exception: e + }); + }); + const CIPHER_KEY = crypto_1.default.createHash('sha256').update(password).digest(); + const decipher = crypto_1.default.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", () => __awaiter(this, void 0, void 0, function* () { + console.log("Sent Full Thumbnail"); + resolve(); + })); + })); + }); + }); + this.publicDownload = (ID, tempToken, res) => { + return new Promise((resolve, reject) => { + dbUtilsFile.getPublicFile(ID).then((file) => __awaiter(this, void 0, void 0, function* () { + if (!file || !file.metadata.link || file.metadata.link !== tempToken) { + reject({ + code: 401, + message: "File not public/Not found", + exception: undefined + }); + } + else { + const user = yield User.findById(file.metadata.owner); + 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(ObjectID(ID)); + readStream.on("error", (e) => { + reject({ + code: 500, + message: "File service public download decipher error", + exception: e + }); + }); + const CIPHER_KEY = crypto_1.default.createHash('sha256').update(password).digest(); + const decipher = crypto_1.default.createDecipheriv('aes256', CIPHER_KEY, IV); + decipher.on("error", (e) => { + reject({ + code: 500, + message: "File service public download 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", () => __awaiter(this, void 0, void 0, function* () { + console.log("removing public link"); + yield this.removePublicOneTimeLink(file); + resolve(); + })); + } + })); + }); + }; + this.removePublicOneTimeLink = (currentFile) => __awaiter(this, void 0, void 0, function* () { + const ID = currentFile._id; + if (currentFile.metadata.linkType === "one") { + yield dbUtilsFile.removeOneTimePublicLink(ID); + } + }); + this.removeLink = (userID, fileID) => __awaiter(this, void 0, void 0, function* () { + const file = yield dbUtilsFile.removeLink(fileID, userID); + if (!file.lastErrorObject.updatedExisting) + throw new NotFoundError("Remove Link File Not Found Error"); + }); + this.makePublic = (user, fileID) => __awaiter(this, void 0, void 0, function* () { + const userID = user._id; + const token = yield jwt.sign({ _id: userID.toString() }, env.password); + const file = yield dbUtilsFile.makePublic(fileID, userID, token, "public"); + if (!file.lastErrorObject.updatedExisting) + throw new NotFoundError("Make Public File Not Found Error"); + return token; + }); + this.getPublicInfo = (fileID, tempToken) => __awaiter(this, void 0, void 0, function* () { + const file = yield dbUtilsFile.getPublicInfo(fileID, tempToken); + if (!file || !file.metadata.link || file.metadata.link !== tempToken) { + throw new NotFoundError("Public Info Not Found"); + } + else { + return file; + } + }); + this.makeOneTimePublic = (userID, fileID) => __awaiter(this, void 0, void 0, function* () { + const token = yield jwt.sign({ _id: userID.toString() }, env.password); + const file = yield dbUtilsFile.makeOneTimePublic(fileID, userID, token); + if (!file.lastErrorObject.updatedExisting) + throw new NotFoundError("Make One Time Public Not Found Error"); + return token; + }); + this.getFileInfo = (userID, fileID) => __awaiter(this, void 0, void 0, function* () { + let currentFile = yield dbUtilsFile.getFileInfo(fileID, userID); + if (!currentFile) + throw new NotFoundError("Get File Info Not Found Error"); + const parentID = currentFile.metadata.parent; + let parentName = ""; + if (parentID === "/") { + parentName = "Home"; + } + else { + const parentFolder = yield Folder.findOne({ "owner": userID, "_id": parentID }); + if (parentFolder) { + parentName = parentFolder.name; + } + else { + parentName = "Unknown"; + } + } + return Object.assign(Object.assign({}, currentFile), { parentName }); + }); + this.getQuickList = (userID) => __awaiter(this, void 0, void 0, function* () { + const quickList = yield dbUtilsFile.getQuickList(userID); + if (!quickList) + throw new NotFoundError("Quick List Not Found Error"); + return quickList; + }); + this.getList = (userID, query) => __awaiter(this, void 0, void 0, function* () { + let searchQuery = query.search || ""; + const parent = query.parent || "/"; + let limit = query.limit || 50; + let sortBy = query.sortby || "DEFAULT"; + const startAt = query.startAt || undefined; + const startAtDate = query.startAtDate || "0"; + const startAtName = query.startAtName || ""; + sortBy = sortBySwitch(sortBy); + limit = parseInt(limit); + const queryObj = createQuery(userID, parent, query.sortby, startAt, startAtDate, searchQuery, startAtName); + const fileList = yield dbUtilsFile.getList(queryObj, sortBy, limit); + if (!fileList) + throw new NotFoundError("File List Not Found"); + return fileList; + }); + this.getDownloadToken = (user) => __awaiter(this, void 0, void 0, function* () { + const tempToken = yield user.generateTempAuthToken(); + if (!tempToken) + throw new NotAuthorizedError("Get Download Token Not Authorized Error"); + return tempToken; + }); + this.getDownloadTokenVideo = (user, cookie) => __awaiter(this, void 0, void 0, function* () { + if (!cookie) + throw new NotAuthorizedError("Get Download Token Video Cookie Not Authorized Error"); + const tempToken = yield user.generateTempAuthTokenVideo(cookie); + if (!tempToken) + throw new NotAuthorizedError("Get Download Token Video Not Authorized Error"); + return tempToken; + }); + this.removeTempToken = (user, tempToken) => __awaiter(this, void 0, void 0, function* () { + const key = user.getEncryptionKey(); + const decoded = yield jwt.verify(tempToken, env.password); + const publicKey = decoded.iv; + const encryptedToken = user.encryptToken(tempToken, key, publicKey); + const removedTokenUser = yield dbUtilsFile.removeTempToken(user, encryptedToken); + if (!removedTokenUser) + throw new NotFoundError("Remove Temp Token User Not Found Errors"); + yield removedTokenUser.save(); + }); + this.transcodeVideo = (user, body) => { + return new Promise((resolve, reject) => { + const id = body.file._id; + const userID = user._id; + conn.db.collection("fs.files") + .findOne({ "_id": ObjectID(id), "metadata.owner": userID }).then((currentFile) => { + if (!currentFile) { + reject({ + message: "Transcode Video Not Found Error", + exception: undefined, + code: 401 + }); + } + else { + const password = user.getEncryptionKey(); //env.key; + const IV = currentFile.metadata.IV.buffer; + const bucket = new mongoose.mongo.GridFSBucket(conn.db); + const readStream = bucket.openDownloadStream(ObjectID(id)); + readStream.on("error", (e) => { + reject({ + message: "File service transcode video stream error", + exception: e, + code: 500 + }); + }); + const CIPHER_KEY = crypto_1.default.createHash('sha256').update(password).digest(); + const decipher = crypto_1.default.createDecipheriv('aes256', CIPHER_KEY, IV); + decipher.on("error", (e) => { + reject({ + message: "File service transcode video decipher error", + exception: e, + code: 500 + }); + }); + const tempStream = temp.createWriteStream(); + tempStream.on("error", (e) => { + reject({ + message: "File service transcode video temp error", + exception: e, + code: 500 + }); + }); + readStream.pipe(decipher).pipe(tempStream).on("finish", () => { + const writeBucket = new mongoose.mongo.GridFSBucket(conn.db, { + bucketName: "videos", + }); + const gfsWrite = writeBucket.openUploadStream(currentFile.filename, { + _id: id, + }); + gfsWrite.on("error", (e) => { + reject({ + message: "File service transcode video write stream error", + exception: e, + code: 500 + }); + }); + const initVect = crypto_1.default.randomBytes(16); + const cipher = crypto_1.default.createCipheriv('aes256', CIPHER_KEY, initVect); + cipher.on("error", (e) => { + reject({ + message: "File service transcode video cipher write error", + exception: e, + code: 500 + }); + }); + const str = progress({ time: 100 }); + str.on("progress", () => { + }); + str.on("finish", () => { + }); + const tempStream2 = temp.createWriteStream(); + tempStream2.on("error", (e) => { + reject({ + message: "File service transcode video temp write error", + exception: e, + code: 500 + }); + }); + const ffmpegCommand = ffmpeg() + .input(tempStream.path).outputOptions(['-movflags frag_keyframe+empty_moov', '-movflags +faststart']) + .outputFormat('mp4').on("error", (err, stdout, stderr) => { + console.log('An error occurred: ' + err.message, err, stderr); + reject({ + message: "Video Transcode Failed Error", + exception: err.message, + code: 500 + }); + }) + .videoCodec('libx264') + .audioBitrate('128k') + .videoBitrate(8000, true) + .pipe(tempStream2).on("finish", () => { + fs.createReadStream(tempStream2.path).pipe(cipher).pipe(gfsWrite).on("finish", (file) => __awaiter(this, void 0, void 0, function* () { + console.log("transcode finished"); + yield conn.db.collection("fs.files") + .findOneAndUpdate({ "_id": ObjectID(id) }, { "$set": { "metadata.transcoded": true, "metadata.transcodedIV": initVect, "metadata.transcoded_size": tempStream2.bytesWritten, "metadata.transcodedID": file._id } }); + resolve(); + })).on("error", (e) => { + reject({ + message: "File service transcode read stream error", + exception: e, + code: 500 + }); + }); + }); + ffmpegCommand.on("error", (e) => { + reject({ + message: "File service FFMPEG error", + exception: e, + code: 500 + }); + }); + }); + } + }); + }); + }; + this.removeTranscodeVideo = (userID, fileID) => __awaiter(this, void 0, void 0, function* () { + const parentFile = yield dbUtilsFile.getFileInfo(fileID, userID); + const transcodedVideoID = parentFile.metadata.transcodedID; + const bucket = new mongoose.mongo.GridFSBucket(conn.db, { + bucketName: "videos" + }); + try { + yield bucket.delete(ObjectID(transcodedVideoID)); + } + catch (e) { + console.log("Could Not Find Transcoded Video"); + } + const file = yield dbUtilsFile.removeTranscodeVideo(fileID, userID); + if (!file) + throw new NotFoundError("Remove Transcode Video Error"); + }); + this.streamTranscodedVideo = (userID, fileID, headers, res) => { + return new Promise((resolve, reject) => { + dbUtilsFile.getFileInfo(fileID, userID).then((file) => { + if (!file) { + reject({ + code: 401, + message: "Stream Transcoded File Not Found", + exception: undefined + }); + } + else { + const fileSize = file.metadata.transcoded_size; + const transcodedVideoID = file.metadata.transcodedID; + const password = user.getEncryptionKey(); //env.key; + const range = headers.range; + const parts = range.replace(/bytes=/, "").split("-"); + const start = parseInt(parts[0], 10); + const end = parts[1] + ? parseInt(parts[1], 10) + : fileSize - 1; + const chunksize = (end - start) + 1; + const IV = file.metadata.transcodedIV.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, { + bucketName: "videos", + chunkSizeBytes: chunksize + }); + const readStream = bucket.openDownloadStream(ObjectID(transcodedVideoID), { + start: start, + end: end + }); + readStream.on("error", (e) => { + reject({ + code: 500, + message: "File service transcode video stream error", + exception: e + }); + }); + const CIPHER_KEY = crypto_1.default.createHash('sha256').update(password).digest(); + const decipher = crypto_1.default.createDecipheriv('aes256', CIPHER_KEY, IV); + decipher.setAutoPadding(false); + decipher.on("error", (e) => { + reject({ + code: 500, + message: "File service transcode video decipher error", + exception: e + }); + }); + res.writeHead(206, head); + readStream.pipe(decipher).pipe(res).on("finish", () => { + resolve(); + }); + } + }); + }); + }; + this.streamVideo = (user, fileID, headers, res) => { + return new Promise((resolve, reject) => { + const userID = user._id; + dbUtilsFile.getFileInfo(fileID, userID).then((currentFile) => { + if (!currentFile) { + reject({ + code: 401, + message: "Video Steam Not Found Error", + exception: undefined + }); + } + else { + const password = user.getEncryptionKey(); + 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(ObjectID(fileID), { + start: start, + end: end.length + }); + readStream.on("error", (e) => { + reject({ + code: 500, + message: "File service stream video stream error", + exception: e + }); + }); + const CIPHER_KEY = crypto_1.default.createHash('sha256').update(password).digest(); + const decipher = crypto_1.default.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(); + }); + } + }); + }); + }; + this.downloadFile = (user, fileID, res) => { + return new Promise((resolve, reject) => { + const userID = user._id; + dbUtilsFile.getFileInfo(fileID, userID).then((file) => { + if (!file) { + reject({ + code: 401, + message: "Download File Not Found Error", + exception: undefined + }); + } + else { + const password = user.getEncryptionKey(); + const bucket = new mongoose.mongo.GridFSBucket(conn.db); + const IV = file.metadata.IV.buffer; + const readStream = bucket.openDownloadStream(ObjectID(fileID)); + readStream.on("error", (e) => { + reject({ + code: 500, + message: "File service download decipher error", + exception: e + }); + }); + const CIPHER_KEY = crypto_1.default.createHash('sha256').update(password).digest(); + const decipher = crypto_1.default.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="' + file.filename + '"'); + res.set('Content-Length', file.metadata.size); + readStream.pipe(decipher).pipe(res).on("finish", () => { + resolve(); + }); + } + }); + }); + }; + this.getSuggestedList = (userID, searchQuery) => __awaiter(this, void 0, void 0, function* () { + searchQuery = new RegExp(searchQuery, 'i'); + const fileList = yield dbUtilsFile.getFileSearchList(userID, searchQuery); + const folderList = yield dbUtilsFolder.getFolderSearchList(userID, searchQuery); + if (!fileList || !folderList) + throw new NotFoundError("Suggested List Not Found Error"); + return { + fileList, + folderList + }; + }); + this.renameFile = (userID, fileID, title) => __awaiter(this, void 0, void 0, function* () { + const file = yield dbUtilsFile.renameFile(fileID, userID, title); + if (!file.lastErrorObject.updatedExisting) + throw new NotFoundError("Rename File Not Found Error"); + return file; + }); + this.moveFile = (userID, fileID, parentID) => __awaiter(this, void 0, void 0, function* () { + let parentList = ["/"]; + if (parentID.length !== 1) { + const parentFile = yield dbUtilsFolder.getFolderInfo(parentID, userID); + if (!parentFile) + throw new NotFoundError("Rename Parent File Not Found Error"); + const parentList = parentFile.parentList; + parentList.push(parentID); + } + const file = yield dbUtilsFile.moveFile(fileID, userID, parentID, parentList.toString()); + if (!file.lastErrorObject.updatedExisting) + throw new NotFoundError("Rename File Not Found Error"); + return file; + }); + this.deleteFile = (userID, fileID) => __awaiter(this, void 0, void 0, function* () { + let bucket = new mongoose.mongo.GridFSBucket(conn.db, { + chunkSizeBytes: 1024 * 255, + }); + const videoBucket = new mongoose.mongo.GridFSBucket(conn.db, { + bucketName: "videos" + }); + const file = yield dbUtilsFile.getFileInfo(fileID, userID); + if (!file) + throw new NotFoundError("Delete File Not Found Error"); + if (file.metadata.thumbnailID) { + yield Thumbnail.deleteOne({ _id: file.metadata.thumbnailID }); + } + if (file.metadata.isVideo && file.metadata.transcoded) { + try { + yield bucket.delete(ObjectID(file.metadata.transcodedID)); + } + catch (e) { + console.log("Could Not Find Transcoded Video"); + } + } + yield bucket.delete(ObjectID(fileID)); + }); +}; +module.exports = FileService; diff --git a/dist/services/FileService/indexnew.js b/dist/services/FileService/indexnew.js new file mode 100644 index 0000000..cc49a43 --- /dev/null +++ b/dist/services/FileService/indexnew.js @@ -0,0 +1,209 @@ +"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 imageChecker = require("../../utils/imageChecker"); +const crypto_1 = __importDefault(require("crypto")); +const videoChecker = require("../../utils/videoChecker"); +const mongoose = require("../../db/mongoose"); +const conn = mongoose.connection; +const createThumbnail = require("../../services/FileService/utils/createThumbnail"); +const thumbnail_1 = __importDefault(require("../../models/thumbnail")); +const ObjectID = require('mongodb').ObjectID; +const NotAuthorizedError_1 = __importDefault(require("../../utils/NotAuthorizedError")); +const NotFoundError_1 = __importDefault(require("../../utils/NotFoundError")); +const env = require("../../enviroment/env"); +const jwt = require("jsonwebtoken"); +const removeChunks = require("./utils/removeChunks"); +const User = require("../../models/user"); +const Folder = require("../../models/folder"); +const sortBySwitch = require("../../utils/sortBySwitch"); +const createQuery = require("../../utils/createQuery"); +const ffmpeg = require("fluent-ffmpeg"); +const temp = require("temp").track(); +const progress = require("progress-stream"); +const fs = require("fs"); +const index_1 = __importDefault(require("../../db/utils/fileUtils/index")); +const DbUtilFolder = require("../../db/utils/folderUtils"); +const dbUtilsFile = new index_1.default(); +const dbUtilsFolder = new DbUtilFolder(); +class MongoFileService { + constructor() { + this.getThumbnail = (user, id) => __awaiter(this, void 0, void 0, function* () { + const password = user.getEncryptionKey(); + const thumbnail = yield thumbnail_1.default.findById(id); + if (thumbnail.owner !== user._id.toString()) { + throw new NotAuthorizedError_1.default('Thumbnail Unauthorized Error'); + } + const iv = thumbnail.data.slice(0, 16); + const chunk = thumbnail.data.slice(16); + const CIPHER_KEY = crypto_1.default.createHash('sha256').update(password).digest(); + const decipher = crypto_1.default.createDecipheriv("aes256", CIPHER_KEY, iv); + const decryptedThumbnail = Buffer.concat([decipher.update(chunk), decipher.final()]); + return decryptedThumbnail; + }); + this.removePublicOneTimeLink = (currentFile) => __awaiter(this, void 0, void 0, function* () { + const fileID = currentFile._id; + if (currentFile.metadata.linkType === "one") { + yield dbUtilsFile.removeOneTimePublicLink(fileID); + } + }); + this.removeLink = (userID, fileID) => __awaiter(this, void 0, void 0, function* () { + const file = yield dbUtilsFile.removeLink(fileID, userID); + if (!file.lastErrorObject.updatedExisting) + throw new NotFoundError_1.default("Remove Link File Not Found Error"); + }); + this.makePublic = (user, fileID) => __awaiter(this, void 0, void 0, function* () { + const userID = user._id; + const token = yield jwt.sign({ _id: userID.toString() }, env.password); + const file = yield dbUtilsFile.makePublic(fileID, userID, token); + if (!file.lastErrorObject.updatedExisting) + throw new NotFoundError_1.default("Make Public File Not Found Error"); + return token; + }); + this.getPublicInfo = (fileID, tempToken) => __awaiter(this, void 0, void 0, function* () { + const file = yield dbUtilsFile.getPublicInfo(fileID, tempToken); + if (!file || !file.metadata.link || file.metadata.link !== tempToken) { + throw new NotFoundError_1.default("Public Info Not Found"); + } + else { + return file; + } + }); + this.makeOneTimePublic = (userID, fileID) => __awaiter(this, void 0, void 0, function* () { + const token = yield jwt.sign({ _id: userID.toString() }, env.password); + const file = yield dbUtilsFile.makeOneTimePublic(fileID, userID, token); + if (!file.lastErrorObject.updatedExisting) + throw new NotFoundError_1.default("Make One Time Public Not Found Error"); + return token; + }); + this.getFileInfo = (userID, fileID) => __awaiter(this, void 0, void 0, function* () { + let currentFile = yield dbUtilsFile.getFileInfo(fileID, userID); + if (!currentFile) + throw new NotFoundError_1.default("Get File Info Not Found Error"); + const parentID = currentFile.metadata.parent; + let parentName = ""; + if (parentID === "/") { + parentName = "Home"; + } + else { + const parentFolder = yield Folder.findOne({ "owner": userID, "_id": parentID }); + if (parentFolder) { + parentName = parentFolder.name; + } + else { + parentName = "Unknown"; + } + } + return Object.assign(Object.assign({}, currentFile), { parentName }); + }); + this.getQuickList = (userID) => __awaiter(this, void 0, void 0, function* () { + const quickList = yield dbUtilsFile.getQuickList(userID); + if (!quickList) + throw new NotFoundError_1.default("Quick List Not Found Error"); + return quickList; + }); + this.getList = (userID, query) => __awaiter(this, void 0, void 0, function* () { + let searchQuery = query.search || ""; + const parent = query.parent || "/"; + let limit = query.limit || 50; + let sortBy = query.sortby || "DEFAULT"; + const startAt = query.startAt || undefined; + const startAtDate = query.startAtDate || "0"; + const startAtName = query.startAtName || ""; + sortBy = sortBySwitch(sortBy); + limit = parseInt(limit); + const queryObj = createQuery(userID, parent, query.sortby, startAt, startAtDate, searchQuery, startAtName); + const fileList = yield dbUtilsFile.getList(queryObj, sortBy, limit); + if (!fileList) + throw new NotFoundError_1.default("File List Not Found"); + return fileList; + }); + this.getDownloadToken = (user) => __awaiter(this, void 0, void 0, function* () { + const tempToken = yield user.generateTempAuthToken(); + if (!tempToken) + throw new NotAuthorizedError_1.default("Get Download Token Not Authorized Error"); + return tempToken; + }); + this.getDownloadTokenVideo = (user, cookie) => __awaiter(this, void 0, void 0, function* () { + if (!cookie) + throw new NotAuthorizedError_1.default("Get Download Token Video Cookie Not Authorized Error"); + const tempToken = yield user.generateTempAuthTokenVideo(cookie); + if (!tempToken) + throw new NotAuthorizedError_1.default("Get Download Token Video Not Authorized Error"); + return tempToken; + }); + this.removeTempToken = (user, tempToken) => __awaiter(this, void 0, void 0, function* () { + const key = user.getEncryptionKey(); + const decoded = yield jwt.verify(tempToken, env.password); + const publicKey = decoded.iv; + const encryptedToken = user.encryptToken(tempToken, key, publicKey); + const removedTokenUser = yield dbUtilsFile.removeTempToken(user, encryptedToken); + if (!removedTokenUser) + throw new NotFoundError_1.default("Remove Temp Token User Not Found Errors"); + yield removedTokenUser.save(); + }); + this.getSuggestedList = (userID, searchQuery) => __awaiter(this, void 0, void 0, function* () { + searchQuery = new RegExp(searchQuery, 'i'); + const fileList = yield dbUtilsFile.getFileSearchList(userID, searchQuery); + const folderList = yield dbUtilsFolder.getFolderSearchList(userID, searchQuery); + if (!fileList || !folderList) + throw new NotFoundError_1.default("Suggested List Not Found Error"); + return { + fileList, + folderList + }; + }); + this.renameFile = (userID, fileID, title) => __awaiter(this, void 0, void 0, function* () { + const file = yield dbUtilsFile.renameFile(fileID, userID, title); + if (!file.lastErrorObject.updatedExisting) + throw new NotFoundError_1.default("Rename File Not Found Error"); + return file; + }); + this.moveFile = (userID, fileID, parentID) => __awaiter(this, void 0, void 0, function* () { + let parentList = ["/"]; + if (parentID.length !== 1) { + const parentFile = yield dbUtilsFolder.getFolderInfo(parentID, userID); + if (!parentFile) + throw new NotFoundError_1.default("Rename Parent File Not Found Error"); + const parentList = parentFile.parentList; + parentList.push(parentID); + } + const file = yield dbUtilsFile.moveFile(fileID, userID, parentID, parentList.toString()); + if (!file.lastErrorObject.updatedExisting) + throw new NotFoundError_1.default("Rename File Not Found Error"); + return file; + }); + this.deleteFile = (userID, fileID) => __awaiter(this, void 0, void 0, function* () { + let bucket = new mongoose.mongo.GridFSBucket(conn.db, { + chunkSizeBytes: 1024 * 255, + }); + const file = yield dbUtilsFile.getFileInfo(fileID, userID); + if (!file) + throw new NotFoundError_1.default("Delete File Not Found Error"); + if (file.metadata.thumbnailID) { + yield thumbnail_1.default.deleteOne({ _id: file.metadata.thumbnailID }); + } + if (file.metadata.isVideo && file.metadata.transcoded) { + try { + yield bucket.delete(ObjectID(file.metadata.transcodedID)); + } + catch (e) { + console.log("Could Not Find Transcoded Video"); + } + } + yield bucket.delete(ObjectID(fileID)); + }); + } +} +exports.default = MongoFileService; diff --git a/dist/services/FileService/utils/createThumbnail.js b/dist/services/FileService/utils/createThumbnail.js new file mode 100644 index 0000000..0ccf56f --- /dev/null +++ b/dist/services/FileService/utils/createThumbnail.js @@ -0,0 +1,65 @@ +"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()); + }); +}; +const mongoose = require("../../../db/mongoose"); +const conn = mongoose.connection; +const crypto = require("crypto"); +const env = require("../../../enviroment/env"); +const Thumbnail = require("../../../models/thumbnail"); +const ObjectID = require('mongodb').ObjectID; +const sharp = require("sharp"); +const concat = require("concat-stream"); +const createThumbnail = (file, filename, user) => __awaiter(void 0, void 0, void 0, function* () { + return new Promise((resolve) => { + const password = user.getEncryptionKey(); + let CIPHER_KEY = crypto.createHash('sha256').update(password).digest(); + let bucket = new mongoose.mongo.GridFSBucket(conn.db, { + chunkSizeBytes: 1024 * 255 + }); + const readStream = bucket.openDownloadStream(ObjectID(file._id)); + readStream.on("error", (e) => { + console.log("File service upload thumbnail error", e); + resolve(file); + }); + const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, file.metadata.IV); + decipher.on("error", (e) => { + console.log("File service upload thumbnail decipher error", e); + resolve(file); + }); + try { + const concatStream = concat((bufferData) => __awaiter(void 0, void 0, void 0, function* () { + const thumbnailIV = crypto.randomBytes(16); + //CIPHER_KEY = crypto.createHash('sha256').update(process.env.newPassword).digest() + const thumbnailCipher = crypto.createCipheriv("aes256", CIPHER_KEY, thumbnailIV); + bufferData = Buffer.concat([thumbnailIV, thumbnailCipher.update(bufferData), thumbnailCipher.final()]); //thumbnailCipher.update(bufferData) + const thumbnailModel = new Thumbnail({ name: filename, owner: user._id, data: bufferData }); + yield thumbnailModel.save(); + let updatedFile = yield conn.db.collection("fs.files") + .findOneAndUpdate({ "_id": file._id }, { "$set": { "metadata.hasThumbnail": true, "metadata.thumbnailID": thumbnailModel._id } }); + updatedFile = updatedFile.value; + updatedFile = Object.assign(Object.assign({}, updatedFile), { metadata: Object.assign(Object.assign({}, updatedFile.metadata), { hasThumbnail: true, thumbnailID: thumbnailModel._id }) }); + resolve(updatedFile); + })).on("error", (e) => { + console.log("File service upload concat stream error", e); + resolve(file); + }); + const imageResize = sharp().resize(300).on("error", (e) => { + console.log("resize error", e); + resolve(file); + }); + readStream.pipe(decipher).pipe(imageResize).pipe(concatStream); + } + catch (e) { + console.log(e); + resolve(file); + } + }); +}); +module.exports = createThumbnail; diff --git a/dist/services/FileService/utils/removeChunks.js b/dist/services/FileService/utils/removeChunks.js new file mode 100644 index 0000000..b39ea56 --- /dev/null +++ b/dist/services/FileService/utils/removeChunks.js @@ -0,0 +1,27 @@ +"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()); + }); +}; +const DbUtilsFile = require("../../../db/utils/fileUtils"); +const dbUtilsFile = new DbUtilsFile(); +const removeChunks = (bucketStream) => __awaiter(void 0, void 0, void 0, function* () { + try { + const uploadID = bucketStream.id; + if (!uploadID || uploadID.length === 0) { + console.log("Invalid uploadID for remove chunks"); + return; + } + yield dbUtilsFile.removeChunksByID(uploadID); + console.log("Upload Request Cancelled, Chunks Removed"); + } + catch (e) { + console.log("Could not remove chunks for canceled upload", uploadID, e); + } +}); +module.exports = removeChunks; diff --git a/dist/services/FolderService/index.js b/dist/services/FolderService/index.js new file mode 100644 index 0000000..6993c00 --- /dev/null +++ b/dist/services/FolderService/index.js @@ -0,0 +1,202 @@ +"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()); + }); +}; +const Folder = require("../../models/folder"); +const InternalServerError = require("../../utils/InternalServerError"); +const NotFoundError = require("../../utils/NotFoundError"); +const UtilsFile = require("../../db/utils/fileUtils"); +const ObjectID = require('mongodb').ObjectID; +const UtilsFolder = require("../../db/utils/folderUtils"); +const mongoose = require("../../db/mongoose"); +const conn = mongoose.connection; +const Thumbnail = require("../../models/thumbnail"); +const sortBySwitch = require("../../utils/sortBySwitchFolder"); +const utilsFile = new UtilsFile(); +const utilsFolder = new UtilsFolder(); +const FolderService = function () { + this.uploadFolder = (data) => __awaiter(this, void 0, void 0, function* () { + const folder = new Folder(data); + yield folder.save(); + if (!folder) + throw new InternalServerError("Upload Folder Error"); + return folder; + }); + this.deleteFolder = (userID, folderID, parentList) => __awaiter(this, void 0, void 0, function* () { + let bucket = new mongoose.mongo.GridFSBucket(conn.db, { + chunkSizeBytes: 1024 * 255 + }); + const videoBucket = new mongoose.mongo.GridFSBucket(conn.db, { + bucketName: "videos" + }); + const parentListString = parentList.toString(); + yield Folder.deleteMany({ "owner": userID, "parentList": { $all: parentList } }); + yield Folder.deleteMany({ "owner": userID, "_id": folderID }); + const fileList = yield utilsFile.getFileListByParent(userID, parentListString); + if (!fileList) + throw new NotFoundError("Delete File List Not Found"); + for (let i = 0; i < fileList.length; i++) { + const currentFile = fileList[i]; + try { + if (currentFile.metadata.thumbnailID) { + yield Thumbnail.deleteOne({ _id: currentFile.metadata.thumbnailID }); + } + if (currentFile.metadata.isVideo && currentFile.metadata.transcoded) { + try { + yield videoBucket.delete(ObjectID(currentFile.metadata.transcodedID)); + } + catch (e) { + console.log("Could Not Find Transcoded Video"); + } + } + yield bucket.delete(ObjectID(currentFile._id)); + } + catch (e) { + console.log("Could not delete file", currentFile.filename, currentFile._id); + } + } + }); + this.deleteAll = (userID) => __awaiter(this, void 0, void 0, function* () { + console.log("remove all request"); + let bucket = new mongoose.mongo.GridFSBucket(conn.db, { + chunkSizeBytes: 1024 * 255 + }); + const videoBucket = new mongoose.mongo.GridFSBucket(conn.db, { + bucketName: "videos" + }); + yield Folder.deleteMany({ "owner": userID }); + const fileList = yield utilsFile.getFileListByOwner(userID); + if (!fileList) + throw new NotFoundError("Delete All File List Not Found Error"); + for (let i = 0; i < fileList.length; i++) { + const currentFile = fileList[i]; + try { + if (currentFile.metadata.thumbnailID) { + yield Thumbnail.deleteOne({ _id: currentFile.metadata.thumbnailID }); + } + if (currentFile.metadata.isVideo && currentFile.metadata.transcoded) { + try { + yield videoBucket.delete(ObjectID(currentFile.metadata.transcodedID)); + } + catch (e) { + console.log("Cannot Find Transcoded Video"); + } + } + yield bucket.delete(ObjectID(currentFile._id)); + } + catch (e) { + console.log("Could Not Remove File", currentFile.filename, currentFile._id); + } + } + }); + this.getFolderInfo = (userID, folderID) => __awaiter(this, void 0, void 0, function* () { + let currentFolder = yield utilsFolder.getFolderInfo(folderID, userID); + if (!currentFolder) + throw new NotFoundError("Folder Info Not Found Error"); + const parentID = currentFolder.parent; + let parentName = ""; + if (parentID === "/") { + parentName = "Home"; + } + else { + const parentFolder = yield utilsFolder.getFolderInfo(parentID, userID); + if (parentFolder) { + parentName = parentFolder.name; + } + else { + parentName = "Unknown"; + } + } + const folderName = currentFolder.name; + currentFolder = Object.assign(Object.assign({}, currentFolder._doc), { parentName, folderName }); + // Must Use ._doc here, or the destucturing/spreading + // Will add a bunch of unneeded variables to the object. + return currentFolder; + }); + this.getFolderSublist = (userID, folderID) => __awaiter(this, void 0, void 0, function* () { + const folder = yield utilsFolder.getFolderInfo(folderID, userID); + if (!folder) + throw new NotFoundError("Folder Sublist Not Found Error"); + const subfolderList = folder.parentList; + let folderIDList = []; + let folderNameList = []; + for (let i = 0; i < subfolderList.length; i++) { + const currentSubFolderID = subfolderList[i]; + if (currentSubFolderID === "/") { + folderIDList.push("/"); + folderNameList.push("Home"); + } + else { + const currentFolder = yield utilsFolder.getFolderInfo(currentSubFolderID, userID); + folderIDList.push(currentFolder._id); + folderNameList.push(currentFolder.name); + } + } + folderIDList.push(folderID); + folderNameList.push(folder.name); + return { + folderIDList, + folderNameList + }; + }); + this.getFolderList = (userID, query) => __awaiter(this, void 0, void 0, function* () { + let searchQuery = query.search || ""; + const parent = query.parent || "/"; + let sortBy = query.sortby || "DEFAULT"; + sortBy = sortBySwitch(sortBy); + if (searchQuery.length === 0) { + const folderList = yield utilsFolder.getFolderListByParent(userID, parent, sortBy); + if (!folderList) + throw new NotFoundError("Folder List Not Found Error"); + return folderList; + } + else { + searchQuery = new RegExp(searchQuery, 'i'); + const folderList = yield utilsFolder.getFolderListBySearch(userID, searchQuery, sortBy); + if (!folderList) + throw new NotFoundError("Folder List Not Found Error"); + return folderList; + } + }); + this.renameFolder = (userID, folderID, title) => __awaiter(this, void 0, void 0, function* () { + const folder = yield utilsFolder.renameFolder(folderID, userID, title); + if (!folder) + throw new NotFoundError("Rename Folder Not Found"); + }); + this.moveFolder = (userID, folderID, parentID) => __awaiter(this, void 0, void 0, function* () { + let parentList = ["/"]; + if (parentID.length !== 1) { + const parentFile = yield utilsFolder.getFolderInfo(parentID, userID); + parentList = parentFile.parentList; + parentList.push(parentID); + } + const folder = yield utilsFolder.moveFolder(folderID, userID, parentID, parentList); + if (!folder) + throw new NotFoundError("Move Folder Not Found"); + const folderChilden = yield utilsFolder.findAllFoldersByParent(folderID.toString(), userID); + folderChilden.map((currentFolderChild) => __awaiter(this, void 0, void 0, function* () { + let currentFolderChildParentList = currentFolderChild.parentList; + const indexOfFolderID = currentFolderChildParentList.indexOf(folderID.toString()); + currentFolderChildParentList = currentFolderChildParentList.splice(indexOfFolderID); + currentFolderChildParentList = [...parentList, ...currentFolderChildParentList]; + currentFolderChild.parentList = currentFolderChildParentList; + yield currentFolderChild.save(); + })); + const fileChildren = yield utilsFile.getFileListByParent(userID, folderID.toString()); + fileChildren.map((currentFileChild) => __awaiter(this, void 0, void 0, function* () { + let currentFileChildParentList = currentFileChild.metadata.parentList; + currentFileChildParentList = currentFileChildParentList.split(","); + const indexOfFolderID = currentFileChildParentList.indexOf(folderID.toString()); + currentFileChildParentList = currentFileChildParentList.splice(indexOfFolderID); + currentFileChildParentList = [...parentList, ...currentFileChildParentList]; + yield utilsFile.moveFile(currentFileChild._id, userID, currentFileChild.metadata.parent, currentFileChildParentList.toString()); + })); + }); +}; +module.exports = FolderService; diff --git a/dist/services/UserService/index.js b/dist/services/UserService/index.js new file mode 100644 index 0000000..2984442 --- /dev/null +++ b/dist/services/UserService/index.js @@ -0,0 +1,62 @@ +"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()); + }); +}; +const User = require("../../models/user"); +const bcrypt = require("bcrypt"); +const crypto = require("crypto"); +const NotFoundError = require("../../utils/NotFoundError"); +const InternalServerError = require("../../utils/InternalServerError"); +const NotAuthorizedError = require("../../utils/NotAuthorizedError"); +const UserService = function () { + this.login = (userData) => __awaiter(this, void 0, void 0, function* () { + const email = userData.email; + const password = userData.password; + const user = yield User.findByCreds(email, password); + const token = yield user.generateAuthToken(); + if (!user || !token) + throw new NotFoundError("Login User Not Found Error"); + return { user, token }; + }); + this.logout = (user, userToken) => __awaiter(this, void 0, void 0, function* () { + user.tokens = user.tokens.filter((token) => { + return token.token !== userToken; + }); + yield user.save(); + }); + this.logoutAll = (user) => __awaiter(this, void 0, void 0, function* () { + user.tokens = []; + user.tempTokens = []; + yield user.save(); + }); + this.create = (userData) => __awaiter(this, void 0, void 0, function* () { + console.log("Create"); + const user = new User(userData); + yield user.save(); + yield user.generateEncryptionKeys(); + const token = yield user.generateAuthToken(); + if (!user || !token) + throw new InternalServerError("Could Not Create New User Error"); + return { user, token }; + }); + this.changePassword = (user, oldPassword, newPassword) => __awaiter(this, void 0, void 0, function* () { + const isMatch = yield bcrypt.compare(oldPassword, user.password); + if (!isMatch) + throw new NotAuthorizedError("Change Passwords Do Not Match Error"); + const encryptionKey = user.getEncryptionKey(); + user.password = newPassword; + user.tokens = []; + user.tempTokens = []; + yield user.save(); + yield user.changeEncryptionKey(encryptionKey); + const newToken = yield user.generateAuthToken(); + return newToken; + }); +}; +module.exports = UserService; diff --git a/dist/test.js b/dist/test.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/dist/test.js @@ -0,0 +1 @@ +"use strict"; diff --git a/dist/utils/InternalServerError.js b/dist/utils/InternalServerError.js new file mode 100644 index 0000000..b54404a --- /dev/null +++ b/dist/utils/InternalServerError.js @@ -0,0 +1,8 @@ +"use strict"; +class InternalServerError extends Error { + constructor(args) { + super(args); + this.code = 500; + } +} +module.exports = InternalServerError; diff --git a/dist/utils/NotAuthorizedError.js b/dist/utils/NotAuthorizedError.js new file mode 100644 index 0000000..05c85c6 --- /dev/null +++ b/dist/utils/NotAuthorizedError.js @@ -0,0 +1,8 @@ +"use strict"; +class NotAuthorizedError extends Error { + constructor(args) { + super(args); + this.code = 401; + } +} +module.exports = NotAuthorizedError; diff --git a/dist/utils/NotFoundError.js b/dist/utils/NotFoundError.js new file mode 100644 index 0000000..daddb1c --- /dev/null +++ b/dist/utils/NotFoundError.js @@ -0,0 +1,8 @@ +"use strict"; +class NotFoundError extends Error { + constructor(args) { + super(args); + this.code = 404; + } +} +module.exports = NotFoundError; diff --git a/dist/utils/createError.js b/dist/utils/createError.js new file mode 100644 index 0000000..e19bcc0 --- /dev/null +++ b/dist/utils/createError.js @@ -0,0 +1,9 @@ +"use strict"; +const createError = (message, code, exception) => { + let error = new Error(message); + error.message = message; + error.code = code; + error.exception = exception; + throw error; +}; +module.exports = createError; diff --git a/dist/utils/createQuery.js b/dist/utils/createQuery.js new file mode 100644 index 0000000..594d1dd --- /dev/null +++ b/dist/utils/createQuery.js @@ -0,0 +1,27 @@ +"use strict"; +const createQuery = (owner, parent, sortBy, startAt, startAtDate, searchQuery, startAtName) => { + let query = { "metadata.owner": owner }; + if (searchQuery !== "") { + searchQuery = new RegExp(searchQuery, 'i'); + query = Object.assign(Object.assign({}, query), { filename: searchQuery }); + } + else { + query = Object.assign(Object.assign({}, query), { "metadata.parent": parent }); + } + if (startAt) { + if (sortBy === "date_desc" || sortBy === "DEFAULT") { + query = Object.assign(Object.assign({}, query), { "uploadDate": { $lt: new Date(startAtDate) } }); + } + else if (sortBy === "date_asc") { + query = Object.assign(Object.assign({}, query), { "uploadDate": { $gt: new Date(startAtDate) } }); + } + else if (sortBy === "alp_desc") { + query = Object.assign(Object.assign({}, query), { "filename": { $lt: startAtName } }); + } + else { + query = Object.assign(Object.assign({}, query), { "filename": { $gt: startAtName } }); + } + } + return query; +}; +module.exports = createQuery; diff --git a/dist/utils/imageChecker.js b/dist/utils/imageChecker.js new file mode 100644 index 0000000..10b76cc --- /dev/null +++ b/dist/utils/imageChecker.js @@ -0,0 +1,22 @@ +"use strict"; +const videoExtList = [ + "jpeg", + "jpg", + "png", + "gif", + "svg", + "tiff", + "bmp" +]; +const videoChecker = (filename) => { + if (filename.length < 1 || !filename.includes(".")) { + return false; + } + const extSplit = filename.split("."); + if (extSplit < 1) { + return false; + } + const ext = extSplit[extSplit.length - 1]; + return videoExtList.includes(ext.toLowerCase()); +}; +module.exports = videoChecker; diff --git a/dist/utils/mobileCheck.js b/dist/utils/mobileCheck.js new file mode 100644 index 0000000..5926377 --- /dev/null +++ b/dist/utils/mobileCheck.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const mobilecheck = () => { + var check = false; + (function (a) { if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) + check = true; })(navigator.userAgent || navigator.vendor || window.opera); + return check; +}; +exports.default = mobilecheck; diff --git a/dist/utils/sortBySwitch.js b/dist/utils/sortBySwitch.js new file mode 100644 index 0000000..08b6927 --- /dev/null +++ b/dist/utils/sortBySwitch.js @@ -0,0 +1,14 @@ +"use strict"; +const sortBySwitch = (sortBy) => { + switch (sortBy) { + case "alp_asc": + return { filename: 1 }; + case "alp_desc": + return { filename: -1 }; + case "date_asc": + return { uploadDate: 1 }; + default: + return { uploadDate: -1 }; + } +}; +module.exports = sortBySwitch; diff --git a/dist/utils/sortBySwitchFolder.js b/dist/utils/sortBySwitchFolder.js new file mode 100644 index 0000000..01f8cd2 --- /dev/null +++ b/dist/utils/sortBySwitchFolder.js @@ -0,0 +1,14 @@ +"use strict"; +const sortBySwitch = (sortBy) => { + switch (sortBy) { + case "alp_asc": + return { name: 1 }; + case "alp_desc": + return { name: -1 }; + case "date_asc": + return { createdAt: 1 }; + default: + return { createdAt: -1 }; + } +}; +module.exports = sortBySwitch; diff --git a/dist/utils/videoChecker.js b/dist/utils/videoChecker.js new file mode 100644 index 0000000..74e8cd4 --- /dev/null +++ b/dist/utils/videoChecker.js @@ -0,0 +1,48 @@ +"use strict"; +const videoExtList = [ + "3g2", + "3gp", + "aaf", + "asf", + "avchd", + "avi", + "drc", + "flv", + "m2v", + "m4p", + "m4v", + "mkv", + "mng", + "mov", + "mp2", + "mp4", + "mpe", + "mpeg", + "mpg", + "mpv", + "mxf", + "nsv", + "ogg", + "ogv", + "qt", + "rm", + "rmvb", + "roq", + "svi", + "vob", + "webm", + "wmv", + "yuv" +]; +const videoChecker = (filename) => { + if (filename.length < 1 || !filename.includes(".")) { + return false; + } + const extSplit = filename.split("."); + if (extSplit < 1) { + return false; + } + const ext = extSplit[extSplit.length - 1]; + return videoExtList.includes(ext.toLowerCase()); +}; +module.exports = videoChecker; diff --git a/package.json b/package.json index 8537a31..36f2029 100755 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "test": "cross-env NODE_ENV=test env-cmd -f ./config/test.env jest --config=jest.config.json --watchAll --runInBand", "start:dev": "env-cmd -f ./config/dev.env node server/serverStart.js", "start": "cross-env NODE_ENV=production env-cmd -f ./config/prod.env node server/serverStart.js --env production", - "start:no-ssl": "cross-env NODE_ENV=production-no-ssl env-cmd -f ./config/prod.env node server/serverStart.js --env production-no-ssl", + "start:no-ssl": "cross-env NODE_ENV=production-no-ssl env-cmd -f ./config/prod.env node dist/server/serverStart.js --env production-no-ssl", "clean-database": "env-cmd -f ./config/prod.env node serverUtils/cleanDatabase.js", "clean-database:dev": "env-cmd -f ./config/dev.env node serverUtils/cleanDatabase.js", "backup-database": "env-cmd -f ./config/prod.env node serverUtils/backupDatabase.js", @@ -32,10 +32,16 @@ }, "dependencies": { "@babel/core": "^7.8.4", + "@babel/parser": "^7.9.4", "@babel/plugin-proposal-class-properties": "^7.8.3", "@babel/plugin-proposal-object-rest-spread": "^7.8.3", "@babel/preset-env": "^7.8.4", "@babel/preset-react": "^7.8.3", + "@babel/types": "^7.9.5", + "@types/express": "^4.17.6", + "@types/mongodb": "^3.5.5", + "@types/mongoose": "^5.7.10", + "@types/node": "^13.11.1", "axios": "^0.19.2", "babel-polyfill": "^6.26.0", "bcrypt": "^3.0.8", @@ -76,6 +82,7 @@ "sharp": "^0.23.4", "sweetalert2": "^9.7.2", "temp": "^0.9.1", + "typescript": "^3.8.3", "uuid": "^3.4.0", "validator": "^12.2.0", "webpack": "^4.41.6" diff --git a/rootpath.js b/rootpath.js deleted file mode 100644 index 68db50e..0000000 --- a/rootpath.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = __dirname \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5d5c7f0 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,74 @@ +{ + "compilerOptions": { + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "module": "CommonJS", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist", /* Redirect output structure to the directory. */ + "rootDir": "./backend", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + }, + "exclude": [ + "serverUtils", + "src", + "tests", + "key", + "public", + "node_modules", + "webpack.config.js", + "dist" + ] +}