@@ -1,3 +1,4 @@
|
||||
|
||||
{
|
||||
"presets": ["@babel/env", "@babel/react"],
|
||||
"plugins": ["@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-object-rest-spread"]
|
||||
|
||||
@@ -3,16 +3,28 @@ import FileService from "../services/FileService";
|
||||
import MongoService from "../services/ChunkService/MongoService";
|
||||
import FileSystemService from "../services/ChunkService/FileSystemService";
|
||||
import S3Service from "../services/ChunkService/S3Service";
|
||||
import {UserInterface} from "../models/user";
|
||||
import uuid from "uuid";
|
||||
import tempStorage from "../tempStorage/tempStorage";
|
||||
import User, {UserInterface} from "../models/user";
|
||||
import sendShareEmail from "../utils/sendShareEmail";
|
||||
import { createStreamVideoCookie, removeStreamVideoCookie } from "../cookies/createCookies";
|
||||
|
||||
const fileService = new FileService()
|
||||
|
||||
interface RequestType extends Request {
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
s3Enabled: boolean,
|
||||
}
|
||||
|
||||
interface RequestTypeFullUser extends Request {
|
||||
user?: UserInterface,
|
||||
auth?: boolean,
|
||||
busboy: any,
|
||||
encryptedToken?: string,
|
||||
accessTokenStreamVideo?: string
|
||||
}
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: userAccessType,
|
||||
encryptedToken?: string
|
||||
}
|
||||
|
||||
type ChunkServiceType = MongoService | FileSystemService | S3Service;
|
||||
@@ -26,8 +38,7 @@ class FileController {
|
||||
this.chunkService = chunkService;
|
||||
}
|
||||
|
||||
getThumbnail = async(req: RequestType, res: Response) => {
|
||||
|
||||
getThumbnail = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
|
||||
@@ -47,15 +58,14 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
console.log("\nGet Thumbnail Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getFullThumbnail = async(req: RequestType, res: Response) => {
|
||||
getFullThumbnail = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
@@ -69,13 +79,14 @@ class FileController {
|
||||
await this.chunkService.getFullThumbnail(user, fileID, res);
|
||||
|
||||
} catch (e) {
|
||||
const code = e.code || 500;
|
||||
console.log(e.message, e.exception)
|
||||
return res.status(code).send();
|
||||
|
||||
console.log("\nGet Thumbnail Full Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
uploadFile = async(req: RequestType, res: Response) => {
|
||||
uploadFile = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
|
||||
@@ -93,12 +104,12 @@ class FileController {
|
||||
|
||||
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();
|
||||
|
||||
console.log("\nUploading File Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.writeHead(code, {'Connection': 'close'})
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,10 +124,8 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
const message = e.message || e;
|
||||
|
||||
console.log(message, e);
|
||||
console.log("\nGet Public Download Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
@@ -138,9 +147,8 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
console.log("\nRemove Public Link Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
@@ -155,17 +163,16 @@ class FileController {
|
||||
try {
|
||||
|
||||
const fileID = req.params.id;
|
||||
const user = req.user;
|
||||
const userID = req.user._id;
|
||||
|
||||
const token = await fileService.makePublic(user, fileID);
|
||||
const token = await fileService.makePublic(userID, fileID);
|
||||
|
||||
res.send(token);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
console.log("\nMake Public Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
@@ -183,10 +190,9 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
console.log("\nGet Public Info Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,10 +213,9 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
console.log("\nMake One Time Public Link Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -232,10 +237,9 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
console.log("\nGet File Info Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,18 +251,17 @@ class FileController {
|
||||
|
||||
try {
|
||||
|
||||
const userID = req.user._id;
|
||||
const user = req.user;
|
||||
|
||||
const quickList = await fileService.getQuickList(userID);
|
||||
const quickList = await fileService.getQuickList(user);
|
||||
|
||||
res.send(quickList);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
console.log("\nGet Quick List Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,23 +273,22 @@ class FileController {
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const query = req.query;
|
||||
const userID = req.user._id;
|
||||
|
||||
const fileList = await fileService.getList(userID, query);
|
||||
const fileList = await fileService.getList(user, query);
|
||||
|
||||
res.send(fileList);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
console.log("\nGet File List Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
getDownloadToken = async(req: RequestType, res: Response) => {
|
||||
getDownloadToken = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return
|
||||
@@ -302,38 +304,88 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
console.log("\nGet Download Token Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
getDownloadTokenVideo = async(req: RequestType, res: Response) => {
|
||||
getAccessTokenStreamVideo = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) return;
|
||||
|
||||
if (!req.user) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
|
||||
const user = req.user;
|
||||
const cookie = req.headers.uuid as string;
|
||||
|
||||
const tempToken = await fileService.getDownloadTokenVideo(user, cookie);
|
||||
|
||||
res.send({tempToken});
|
||||
|
||||
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
|
||||
const streamVideoAccessToken = await user.generateAuthTokenStreamVideo(currentUUID);
|
||||
|
||||
createStreamVideoCookie(res, streamVideoAccessToken);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
console.log("\nGet Access Token Stream Video Fle Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
}
|
||||
|
||||
removeStreamVideoAccessToken = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) return;
|
||||
|
||||
try {
|
||||
|
||||
const userID = req.user._id;
|
||||
|
||||
const accessTokenStreamVideo = req.accessTokenStreamVideo!;
|
||||
|
||||
await User.updateOne({_id: userID}, {$pull: {tempTokens: {token: accessTokenStreamVideo}}});
|
||||
|
||||
removeStreamVideoCookie(res);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\Remove Video Token File Router Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
removeTempToken = async(req: RequestType, res: Response) => {
|
||||
// No longer needed, left for reference
|
||||
|
||||
// getDownloadTokenVideo = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
// if (!req.user) {
|
||||
// return
|
||||
// }
|
||||
|
||||
// try {
|
||||
|
||||
// const user = req.user;
|
||||
// const cookie = req.headers.uuid as string;
|
||||
|
||||
// const tempToken = await fileService.getDownloadTokenVideo(user, cookie);
|
||||
|
||||
// res.send({tempToken});
|
||||
|
||||
// } catch (e) {
|
||||
|
||||
// const code = e.code || 500;
|
||||
|
||||
// console.log(e);
|
||||
// res.status(code).send()
|
||||
// }
|
||||
// }
|
||||
|
||||
removeTempToken = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return
|
||||
@@ -351,16 +403,15 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
console.log("\nRemove Temp Token Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
streamVideo = async(req: RequestType, res: Response) => {
|
||||
streamVideo = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.auth || !req.user) {
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -370,43 +421,25 @@ class FileController {
|
||||
const fileID = req.params.id;
|
||||
const headers = req.headers;
|
||||
|
||||
//tempStorage[req.params.uuid] = uuid.v4();
|
||||
|
||||
console.log("stream request 2", tempStorage);
|
||||
|
||||
// req.on("close", () => {
|
||||
// console.log("req closed stream");
|
||||
// })
|
||||
|
||||
// req.on("abort", () => {
|
||||
// console.log("Aborted");
|
||||
// })
|
||||
|
||||
await this.chunkService.streamVideo(user, fileID, headers, res, req);
|
||||
|
||||
//console.log("stream finished");
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
const message = e.message || e;
|
||||
|
||||
console.log(message, e);
|
||||
console.log("\nStream Video Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
downloadFile = async(req: RequestType, res: Response) => {
|
||||
downloadFile = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.auth || !req.user) {
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
console.log("download request")
|
||||
|
||||
const user = req.user;
|
||||
const fileID = req.params.id;
|
||||
|
||||
@@ -414,10 +447,8 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
const message = e.message || e;
|
||||
|
||||
console.log(message, e);
|
||||
console.log("\nDownload File Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
@@ -440,10 +471,9 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
console.log("\nGet Suggested List Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,17 +495,41 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
console.log("\nRename File Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
moveFile = async(req: RequestType, res: Response) => {
|
||||
sendEmailShare = async(req: RequestType, res: Response) => {
|
||||
|
||||
console.log("move request");
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user!;
|
||||
|
||||
const fileID = req.body.file._id;
|
||||
const respient = req.body.file.resp;
|
||||
|
||||
const file = await fileService.getFileInfo(user._id, fileID);
|
||||
|
||||
await sendShareEmail(file, respient)
|
||||
|
||||
res.send()
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nSend Share Email Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
moveFile = async(req: RequestType, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
@@ -486,8 +540,6 @@ class FileController {
|
||||
const fileID = req.body.id;
|
||||
const userID = req.user._id;
|
||||
const parentID = req.body.parent;
|
||||
|
||||
console.log(fileID, userID, parentID);
|
||||
|
||||
await fileService.moveFile(userID, fileID, parentID);
|
||||
|
||||
@@ -495,10 +547,9 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
console.log("\nMove File Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -520,10 +571,9 @@ class FileController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send()
|
||||
console.log("\nDelete File Error File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import FolderService from "../services/FolderService";
|
||||
import { Request, Response } from "express";
|
||||
import {UserInterface} from "../models/user";
|
||||
import MongoService from "../services/ChunkService/MongoService";
|
||||
import FileSystemService from "../services/ChunkService/FileSystemService";
|
||||
import S3Service from "../services/ChunkService/S3Service";
|
||||
|
||||
const folderService = new FolderService();
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
s3Enabled: boolean,
|
||||
}
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: UserInterface,
|
||||
user?: userAccessType,
|
||||
encryptedToken?: string
|
||||
}
|
||||
|
||||
type ChunkServiceType = MongoService | FileSystemService | S3Service;
|
||||
@@ -39,10 +46,9 @@ class FolderController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send(e);
|
||||
console.log("\nUpload Folder Error Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,10 +71,60 @@ class FolderController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500
|
||||
console.log("\nDelete Folder Error Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send(e);
|
||||
getSubfolderFullList = async(req: RequestType, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
|
||||
const user = req.user;
|
||||
const id: any = req.query.id;
|
||||
|
||||
const subfolderList = await folderService.getSubfolderFullList(user, id);
|
||||
|
||||
res.send(subfolderList);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Subfolder List Error Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
deletePersonalFolder = async(req: RequestType, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const userID = req.user._id;
|
||||
const folderID = req.body.id;
|
||||
const parentList = req.body.parentList
|
||||
|
||||
const s3Service = new S3Service();
|
||||
|
||||
await s3Service.deleteFolder(userID, folderID, parentList);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nDelete Personal Folder Error Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,10 +145,9 @@ class FolderController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send(e);
|
||||
console.log("\nDelete All Error Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,10 +168,9 @@ class FolderController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send(e);
|
||||
console.log("\nGet Info Error Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,10 +192,9 @@ class FolderController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send(e);
|
||||
console.log("\nGet Subfolder Error Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,19 +207,18 @@ class FolderController {
|
||||
|
||||
try {
|
||||
|
||||
const userID = req.user._id;
|
||||
const user = req.user;
|
||||
const query = req.query;
|
||||
|
||||
const folderList = await folderService.getFolderList(userID, query);
|
||||
const folderList = await folderService.getFolderList(user, query);
|
||||
|
||||
res.send(folderList);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send(e);
|
||||
console.log("\nGet Folder List Error Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,11 +240,9 @@ class FolderController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send(e);
|
||||
|
||||
console.log("\nMove Folder Error Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,11 +264,9 @@ class FolderController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send(e);
|
||||
|
||||
console.log("\nRename Folder Error Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
import { Request, Response } from "express";
|
||||
import {UserInterface} from "../models/user";
|
||||
import GoogleFileService from "../services/GoogleFileService";
|
||||
import { googleQueryType } from "../utils/createQueryGoogle";
|
||||
|
||||
const googleFileService = new GoogleFileService();
|
||||
|
||||
interface RequestTypeFullUser extends Request {
|
||||
user?: UserInterface,
|
||||
encryptedToken?: string
|
||||
}
|
||||
|
||||
class GoogleFileController {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
getList = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const query = req.query as unknown as googleQueryType;
|
||||
|
||||
const googleFiles = await googleFileService.getList(user, query);
|
||||
|
||||
res.send(googleFiles)
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Google List Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
getMongoGoogleList = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const query = req.query as unknown as googleQueryType;
|
||||
|
||||
const mongoGoogleFiles = await googleFileService.getMongoGoogleList(user, query);
|
||||
|
||||
res.send(mongoGoogleFiles)
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Google/Mongo List Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
getFileInfo = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const id: any = req.params.id;
|
||||
const user = req.user;
|
||||
|
||||
const fileInfo = await googleFileService.getFileInfo(user, id);
|
||||
|
||||
res.send(fileInfo);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Info Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
getGoogleMongoQuickList = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
|
||||
const googleMongoQuickList = await googleFileService.getGoogleMongoQuickList(user);
|
||||
|
||||
res.send(googleMongoQuickList);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Google/Mongo Quicklist Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
getGoogleMongoSuggestedList = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
|
||||
const searchQuery: any = req.query.search || "";
|
||||
|
||||
const fileAndFolderList = await googleFileService.getGoogleMongoSuggestedList(user, searchQuery);
|
||||
|
||||
res.send(fileAndFolderList);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Google/Mongo Suggested List Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
renameFile = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const fileID = req.body.id;
|
||||
const title = req.body.title
|
||||
|
||||
await googleFileService.renameFile(user, fileID, title);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nRename File Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
removeFile = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const fileID = req.body.id;
|
||||
const user = req.user!;
|
||||
|
||||
await googleFileService.removeFile(user, fileID);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nRemove File Error Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
downloadFile = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user!;
|
||||
const fileID = req.params.id;
|
||||
|
||||
await googleFileService.downloadFile(user, fileID, res);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nDownload File Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
downloadDoc = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const fileID = req.params.id;
|
||||
|
||||
await googleFileService.downloadDoc(user, fileID, res);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nDownload Doc Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
getThumbnail = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const fileID = req.params.id;
|
||||
|
||||
await googleFileService.getThumbnail(user, fileID, res);
|
||||
|
||||
} catch(e) {
|
||||
|
||||
console.log("\nGet Thumbnail Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getFulllThumbnail = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const fileID = req.params.id;
|
||||
|
||||
await googleFileService.getFullThumbnail(user, fileID, res);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Full Thumbnail Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
streamVideo = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user!;
|
||||
const fileID = req.params.id;
|
||||
const tempUUID = req.params.uuid;
|
||||
|
||||
await googleFileService.streamVideo(user, fileID, tempUUID, req, res);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nStream Video Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
uploadFile = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const busboy = req.busboy;
|
||||
|
||||
req.pipe(busboy);
|
||||
|
||||
await googleFileService.uploadFile(user, busboy, req, res);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nUpload File Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
moveFile = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user!;
|
||||
const fileID = req.body.id;
|
||||
const parentID = req.body.parent;
|
||||
|
||||
await googleFileService.moveFile(user, fileID, parentID);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nMove File Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
makeFilePublic = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const fileID = req.params.id;
|
||||
|
||||
const publicURL = await googleFileService.makeFilePublic(user, fileID);
|
||||
|
||||
res.send(publicURL);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nMake Public Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
removePublicLink = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user!;
|
||||
const fileID = req.params.id;
|
||||
|
||||
await googleFileService.removePublicLink(user, fileID);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nRemove Public Error Google File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default GoogleFileController;
|
||||
@@ -0,0 +1,230 @@
|
||||
import { Request, Response } from "express";
|
||||
import {UserInterface} from "../models/user";
|
||||
import GoogleFolderService from "../services/GoogleFolderService";
|
||||
import { googleQueryType } from "../utils/createQueryGoogle";
|
||||
|
||||
const googleFolderService = new GoogleFolderService();
|
||||
|
||||
interface RequestTypeFullUser extends Request {
|
||||
user?: UserInterface,
|
||||
encryptedToken?: string
|
||||
}
|
||||
|
||||
class GoogleFolderController {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
getList = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const query = req.query as unknown as googleQueryType;
|
||||
|
||||
const folderList = await googleFolderService.getList(user, query);
|
||||
|
||||
res.send(folderList);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Google List Error Google Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
getGoogleMongoList = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const query = req.query;
|
||||
|
||||
const folderList = await googleFolderService.getGoogleMongoList(user, query);
|
||||
|
||||
res.send(folderList);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Google/Mongo List Error Google Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
getInfo = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const id = req.params.id;
|
||||
|
||||
const folderInfo = await googleFolderService.getInfo(user, id);
|
||||
|
||||
res.send(folderInfo);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Info Error Google Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
getSubFolderList = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const id: any = req.query.id;
|
||||
|
||||
const nameAndIDList = await googleFolderService.getSubFolderList(user, id);
|
||||
|
||||
res.send(nameAndIDList);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Subfolder List Error Google Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getSubfolderFullList = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const id: any = req.query.id;
|
||||
|
||||
const fullSubfolderList = await googleFolderService.getSubFolderFullList(user, id);
|
||||
|
||||
res.send(fullSubfolderList);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Full Subfolder List Error Google Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
renameFolder = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const folderID = req.body.id;
|
||||
const title = req.body.title
|
||||
|
||||
await googleFolderService.renameFolder(user, folderID, title);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nRename Folder Error Google Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
removeFolder = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const folderID = req.body.id;
|
||||
|
||||
await googleFolderService.removeFolder(user, folderID)
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nRemove Folder Error Google Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
upload = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
let {name, parent} = req.body;
|
||||
|
||||
const createdFolder = await googleFolderService.upload(user, name, parent);
|
||||
|
||||
res.send(createdFolder);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nUpload Folder Error Google Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
moveFolder = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const folderID = req.body.id;
|
||||
const parentID = req.body.parent;
|
||||
|
||||
await googleFolderService.moveFolder(user, folderID, parentID);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nMove Folder Error Google Folder Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default GoogleFolderController;
|
||||
@@ -0,0 +1,202 @@
|
||||
import S3Service from "../services/ChunkService/S3Service";
|
||||
import { Request, Response } from "express";
|
||||
import {UserInterface} from "../models/user";
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
s3Enabled: boolean,
|
||||
}
|
||||
|
||||
interface RequestTypeFullUser extends Request {
|
||||
user?: UserInterface,
|
||||
encryptedToken?: string
|
||||
}
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: userAccessType,
|
||||
encryptedToken?: string
|
||||
}
|
||||
|
||||
|
||||
class PersonalFileController {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
getPersonalThumbnail = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
|
||||
if (!req.user) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const s3Service = new S3Service();
|
||||
|
||||
const user = req.user;
|
||||
const id = req.params.id;
|
||||
|
||||
const decryptedThumbnail = await s3Service.getThumbnail(user, id);
|
||||
|
||||
|
||||
res.send(decryptedThumbnail);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Thumbnail Error Personal File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getFullPersonalThumbnail = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const s3Service = new S3Service();
|
||||
|
||||
const user = req.user;
|
||||
const fileID = req.params.id;
|
||||
|
||||
await s3Service.getFullThumbnail(user, fileID, res);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Full Thumbnail Error Personal File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
uploadPersonalFile = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const s3Service = new S3Service();
|
||||
|
||||
const user = req.user;
|
||||
const busboy = req.busboy;
|
||||
|
||||
req.pipe(busboy);
|
||||
|
||||
const file = await s3Service.uploadFile(user, busboy, req);
|
||||
|
||||
res.send(file);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nUpload File Error Personal File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
getPublicPersonalDownload = async(req: RequestType, res: Response) => {
|
||||
|
||||
try {
|
||||
|
||||
const ID = req.params.id;
|
||||
const tempToken = req.params.tempToken;
|
||||
|
||||
const s3Service = new S3Service();
|
||||
|
||||
await s3Service.getPublicDownload(ID, tempToken, res);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Public Download Error Personal File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
streamPersonalVideo = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const fileID = req.params.id;
|
||||
const headers = req.headers;
|
||||
|
||||
const s3Service = new S3Service();
|
||||
|
||||
await s3Service.streamVideo(user, fileID, headers, res, req);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nStream Video Error Personal File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
downloadPersonalFile = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const s3Service = new S3Service();
|
||||
|
||||
const user = req.user;
|
||||
const fileID = req.params.id;
|
||||
|
||||
await s3Service.downloadFile(user, fileID, res);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nDownload File Error Personal File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
deletePersonalFile = async(req: RequestType, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const s3Service = new S3Service();
|
||||
|
||||
const userID = req.user._id;
|
||||
const fileID = req.body.id;
|
||||
|
||||
await s3Service.deleteFile(userID, fileID);
|
||||
|
||||
res.send()
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nDelete File Error Personal File Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default PersonalFileController;
|
||||
@@ -3,8 +3,16 @@ import env from "../enviroment/env";
|
||||
import { Request, Response } from "express";
|
||||
import { UserInterface } from "../models/user";
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
s3Enabled: boolean,
|
||||
}
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: UserInterface,
|
||||
user?: userAccessType,
|
||||
encryptedToken?: string
|
||||
}
|
||||
|
||||
class StorageController {
|
||||
@@ -32,8 +40,9 @@ class StorageController {
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log(e);
|
||||
res.status(500).send(e);
|
||||
console.log("\nGet Storage Error Storage Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,31 @@ import env from "../enviroment/env";
|
||||
import UserService from "../services/UserService";
|
||||
import { Request, Response } from "express";
|
||||
import { UserInterface } from "../models/user";
|
||||
import { createLoginCookie, createLogoutCookie } from "../cookies/createCookies";
|
||||
import NotFoundError from "../utils/NotFoundError";
|
||||
import InternalServerError from "../utils/InternalServerError";
|
||||
|
||||
const UserProvider = new UserService();
|
||||
|
||||
interface RequestType extends Request {
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
admin: boolean,
|
||||
botChecked: boolean,
|
||||
username: string,
|
||||
}
|
||||
|
||||
interface RequestTypeRefresh extends Request {
|
||||
user?: UserInterface,
|
||||
encryptedToken?: string
|
||||
}
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: userAccessType,
|
||||
encryptedToken?: string
|
||||
}
|
||||
|
||||
class UserController {
|
||||
|
||||
constructor() {
|
||||
@@ -21,17 +39,14 @@ class UserController {
|
||||
try {
|
||||
|
||||
const user = req.user!;
|
||||
user.tokens = [];
|
||||
user.tempTokens = [];
|
||||
user.password = '';
|
||||
user.privateKey = undefined;
|
||||
user.publicKey = undefined;
|
||||
|
||||
res.send(user)
|
||||
|
||||
} catch (e) {
|
||||
|
||||
res.status(500).send(e);
|
||||
console.log("\nGet User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,23 +55,46 @@ class UserController {
|
||||
try {
|
||||
|
||||
const body = req.body;
|
||||
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
|
||||
const {user, token} = await UserProvider.login(body);
|
||||
const {user, accessToken, refreshToken} = await UserProvider.login(body, currentUUID);
|
||||
|
||||
user.tokens = [];
|
||||
user.tempTokens = [];
|
||||
user.password = '';
|
||||
user.privateKey = undefined;
|
||||
user.publicKey = undefined;
|
||||
|
||||
res.status(200).send({user, token});
|
||||
createLoginCookie(res, accessToken, refreshToken);
|
||||
|
||||
res.status(200).send({user});
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
console.log("\nLogin User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send(e);
|
||||
getToken = async(req: RequestTypeRefresh, res: Response) => {
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
|
||||
if (!user) throw new NotFoundError("User Not Found");
|
||||
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
|
||||
const {accessToken, refreshToken} = await user.generateAuthToken(currentUUID);
|
||||
|
||||
if (!accessToken || !refreshToken) throw new InternalServerError("User/Access/Refresh Token Missing");
|
||||
|
||||
createLoginCookie(res, accessToken, refreshToken);
|
||||
|
||||
res.status(201).send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet Refresh Token User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,32 +107,43 @@ class UserController {
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const token = req.encryptedToken;
|
||||
const userID = req.user._id;
|
||||
const refreshToken = req.cookies["refresh-token"];
|
||||
|
||||
await UserProvider.logout(user, token);
|
||||
await UserProvider.logout(userID, refreshToken);
|
||||
|
||||
createLogoutCookie(res);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
res.status(500).send(e);
|
||||
console.log("\nLogout User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
createLogoutCookie(res);
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
logoutAll = async(req: RequestType, res: Response) => {
|
||||
|
||||
if (!req.user) return;
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const userID = req.user._id;
|
||||
|
||||
await UserProvider.logoutAll(user!);
|
||||
await UserProvider.logoutAll(userID);
|
||||
|
||||
createLogoutCookie(res);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
res.status(500).send(e);
|
||||
console.log("\nLogout All User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,22 +156,19 @@ class UserController {
|
||||
|
||||
try {
|
||||
|
||||
const {user, token} = await UserProvider.create(req.body);
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
|
||||
user.tokens = [];
|
||||
user.tempTokens = []
|
||||
user.password = '';
|
||||
user.privateKey = undefined;
|
||||
user.publicKey = undefined;
|
||||
const {user, accessToken, refreshToken} = await UserProvider.create(req.body, currentUUID);
|
||||
|
||||
createLoginCookie(res, accessToken, refreshToken);
|
||||
|
||||
res.status(201).send({user, token})
|
||||
res.status(201).send({user})
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send(e);
|
||||
console.log("\nCreate User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,21 +180,175 @@ class UserController {
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
|
||||
const userID = req.user._id;
|
||||
const oldPassword = req.body.oldPassword;
|
||||
const newPassword = req.body.newPassword;
|
||||
|
||||
const newToken = await UserProvider.changePassword(user, oldPassword, newPassword);
|
||||
const oldRefreshToken = req.cookies["refresh-token"];
|
||||
|
||||
res.send(newToken);
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
|
||||
const {accessToken, refreshToken} = await UserProvider.changePassword(userID, oldPassword, newPassword, oldRefreshToken, currentUUID);
|
||||
|
||||
createLoginCookie(res, accessToken, refreshToken);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
const code = e.code || 500;
|
||||
console.log("\nChange Password User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
console.log(e);
|
||||
res.status(code).send(e);
|
||||
refreshStorageSize = async(req: RequestType, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const userID = req.user._id;
|
||||
|
||||
await UserProvider.refreshStorageSize(userID);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nRefresh Storage Size User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
getUserDetailed = async(req: RequestType, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const userID = req.user._id;
|
||||
|
||||
const userDetailed = await UserProvider.getUserDetailed(userID);
|
||||
|
||||
res.send(userDetailed);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nGet User Detailed User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
verifyEmail = async(req: RequestType, res: Response) => {
|
||||
|
||||
try {
|
||||
|
||||
const verifyToken = req.body.emailToken;
|
||||
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
|
||||
const user = await UserProvider.verifyEmail(verifyToken);
|
||||
|
||||
const {accessToken, refreshToken} = await user.generateAuthToken(currentUUID);
|
||||
|
||||
createLoginCookie(res, accessToken, refreshToken);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nVerify Email User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
resendVerifyEmail = async(req: RequestType, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const userID = req.user._id;
|
||||
|
||||
await UserProvider.resendVerifyEmail(userID);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nResend Email User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
sendPasswordReset = async(req: RequestType, res: Response) => {
|
||||
|
||||
try {
|
||||
|
||||
const email = req.body.email;
|
||||
|
||||
await UserProvider.sendPasswordReset(email);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nSend Password Reset Email User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
resetPassword = async(req: RequestType, res: Response) => {
|
||||
|
||||
try {
|
||||
|
||||
const verifyToken = req.body.passwordToken;
|
||||
const newPassword = req.body.password;
|
||||
|
||||
await UserProvider.resetPassword(newPassword, verifyToken);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nReset Password User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
addName = async(req: RequestType, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const userID = req.user._id;
|
||||
const name = req.body.name;
|
||||
|
||||
await UserProvider.addName(userID, name);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nAdd Name User Route Error:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import { Request, Response } from "express";
|
||||
import { UserInterface } from "../models/user";
|
||||
import UserServiceGoogle from "../services/UserGoogle";
|
||||
import { createLoginCookie } from "../cookies/createCookies";
|
||||
|
||||
const UserProviderGoogle = new UserServiceGoogle();
|
||||
|
||||
interface RequestTypeFullUser extends Request {
|
||||
user?: UserInterface,
|
||||
encryptedToken?: string
|
||||
}
|
||||
|
||||
class UserGoogleController {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
createGoogleStorageURL = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const googleData = req.body;
|
||||
|
||||
const url = await UserProviderGoogle.createGoogleStorageURL(user, googleData);
|
||||
|
||||
res.send(url);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nCreate Storage URL Error Google User Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
addGoogleStorage = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const code = req.body.code;
|
||||
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
|
||||
const {accessToken, refreshToken} = await UserProviderGoogle.addGoogleStorage(user, code, currentUUID);
|
||||
|
||||
createLoginCookie(res, accessToken, refreshToken);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nAdd Google Storage Error Google User Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
removeGoogleStorage = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user
|
||||
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
|
||||
const {accessToken, refreshToken} = await UserProviderGoogle.removeGoogleStorage(user, currentUUID);
|
||||
|
||||
createLoginCookie(res, accessToken, refreshToken);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nRemove Google Storage Error Google User Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default UserGoogleController;
|
||||
@@ -0,0 +1,156 @@
|
||||
import { Request, Response } from "express";
|
||||
import { UserInterface } from "../models/user";
|
||||
import UserServicePersonal from "../services/UserPersonalService";
|
||||
import { createLoginCookie } from "../cookies/createCookies";
|
||||
|
||||
const UserProviderPersonal = new UserServicePersonal()
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
s3Enabled: boolean,
|
||||
}
|
||||
|
||||
interface RequestTypeFullUser extends Request {
|
||||
user?: UserInterface,
|
||||
encryptedToken?: string
|
||||
}
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: userAccessType,
|
||||
encryptedToken?: string
|
||||
}
|
||||
|
||||
class UserPersonalController {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
addS3Storage = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const s3Data = req.body;
|
||||
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
|
||||
const {accessToken, refreshToken} = await UserProviderPersonal.addS3Storage(user, s3Data, currentUUID);
|
||||
|
||||
createLoginCookie(res, accessToken, refreshToken);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nAdd S3 Storage Error Personal User Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
removeS3Storage = async(req: RequestTypeFullUser, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
|
||||
const {accessToken, refreshToken} = await UserProviderPersonal.removeS3Storage(user, currentUUID);
|
||||
|
||||
createLoginCookie(res, accessToken, refreshToken);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nRemove S3 Storage Error Personal User Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
removeS3Metadata = async(req: RequestType, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
|
||||
await UserProviderPersonal.removeS3Metadata(user);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nRemove S3 Metadata Error Personal User Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
downloadPersonalFileList = async(req: RequestType, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
|
||||
res.set('Content-Type', 'application/json');
|
||||
res.setHeader('Content-disposition', 'attachment; filename= personal-data-list.json');
|
||||
|
||||
const personalFileList = await UserProviderPersonal.downloadPersonalFileList(user);
|
||||
|
||||
res.send(personalFileList);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nDownload S3 Metadata Error Personal User Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
|
||||
uploadPersonalFileList = async(req: RequestType, res: Response) => {
|
||||
|
||||
if (!req.user) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const user = req.user;
|
||||
const fileList = req.body;
|
||||
|
||||
await UserProviderPersonal.uploadPersonalFileList(user, fileList);
|
||||
|
||||
res.send();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log("\nUpload S3 Metadata Error Personal User Route:", e.message);
|
||||
const code = !e.code ? 500 : e.code >= 400 && e.code <= 599 ? e.code : 500;
|
||||
res.status(code).send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default UserPersonalController;
|
||||
@@ -0,0 +1,64 @@
|
||||
import {Response } from "express";
|
||||
import env from "../enviroment/env";
|
||||
|
||||
const maxAgeAccess = 60 * 1000 * 20;
|
||||
//const maxAgeAccess = 1000;
|
||||
const maxAgeRefresh = 60 * 1000 * 60 * 24 * 30;
|
||||
//const maxAgeRefresh = 1000;
|
||||
const maxAgeStreamVideo = 60 * 1000 * 60 * 24;
|
||||
|
||||
const secureCookies = env.secureCookies ? env.secureCookies === "true" ? true : false : false;
|
||||
|
||||
export const createLoginCookie = (res: Response, accessToken: string, refreshToken: string) => {
|
||||
|
||||
res.cookie("access-token",accessToken, {
|
||||
httpOnly: true,
|
||||
maxAge: maxAgeAccess,
|
||||
sameSite: "strict",
|
||||
secure: secureCookies
|
||||
})
|
||||
|
||||
res.cookie("refresh-token",refreshToken, {
|
||||
httpOnly: true,
|
||||
maxAge: maxAgeRefresh,
|
||||
sameSite: "strict",
|
||||
secure: secureCookies
|
||||
})
|
||||
}
|
||||
|
||||
export const createLogoutCookie = (res: Response) => {
|
||||
|
||||
res.cookie("access-token", {}, {
|
||||
httpOnly: true,
|
||||
maxAge: 0,
|
||||
sameSite: "strict",
|
||||
secure: secureCookies
|
||||
})
|
||||
|
||||
res.cookie("refresh-token", {}, {
|
||||
httpOnly: true,
|
||||
maxAge: 0,
|
||||
sameSite: "strict",
|
||||
secure: secureCookies
|
||||
})
|
||||
}
|
||||
|
||||
export const createStreamVideoCookie = (res: Response, streamVideoAccessToken: string) => {
|
||||
|
||||
res.cookie("video-access-token", streamVideoAccessToken, {
|
||||
httpOnly: true,
|
||||
maxAge: maxAgeStreamVideo,
|
||||
sameSite: "strict",
|
||||
secure: secureCookies
|
||||
})
|
||||
}
|
||||
|
||||
export const removeStreamVideoCookie = (res: Response) => {
|
||||
|
||||
res.cookie("video-access-token", {}, {
|
||||
httpOnly: true,
|
||||
maxAge: 0,
|
||||
sameSite: "strict",
|
||||
secure: secureCookies
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import AWS from "aws-sdk";
|
||||
|
||||
const s3Auth = (id:string, key:string) => {
|
||||
|
||||
AWS.config.update({
|
||||
accessKeyId: id,
|
||||
secretAccessKey: key
|
||||
});
|
||||
|
||||
const s3 = new AWS.S3();
|
||||
|
||||
return s3;
|
||||
}
|
||||
|
||||
|
||||
export default s3Auth;
|
||||
@@ -0,0 +1,35 @@
|
||||
import { UserInterface } from "../models/user";
|
||||
import {google} from "googleapis";
|
||||
import env from "../enviroment/env";
|
||||
|
||||
const getGoogleAuth = async (user: UserInterface) => {
|
||||
|
||||
const googleIDandToken = await user?.decryptDriveIDandKey();
|
||||
|
||||
const clientID = googleIDandToken?.clientID;
|
||||
const clientKey = googleIDandToken?.clientKey;
|
||||
const token = await user?.decryptDriveTokenData();
|
||||
const refreshToken = token.refresh_token;
|
||||
|
||||
|
||||
const date = new Date();
|
||||
const time = date.getTime();
|
||||
|
||||
if (time >= token.expiry_date) {
|
||||
// console.log("TOKEN EXPIRED!")
|
||||
}
|
||||
|
||||
const redirectURL = env.remoteURL + "/add-google-account";
|
||||
|
||||
const oauth2Client = new google.auth.OAuth2(
|
||||
clientID,
|
||||
clientKey,
|
||||
redirectURL,
|
||||
);
|
||||
|
||||
oauth2Client.setCredentials(token);
|
||||
|
||||
return oauth2Client
|
||||
}
|
||||
|
||||
export default getGoogleAuth;
|
||||
@@ -8,4 +8,5 @@ AWS.config.update({
|
||||
|
||||
const s3 = new AWS.S3();
|
||||
|
||||
export default s3;
|
||||
export default s3;
|
||||
module.exports = s3;
|
||||
@@ -32,7 +32,7 @@ class DbUtil {
|
||||
|
||||
const file = await conn.db.collection("fs.files")
|
||||
.findOneAndUpdate({"_id": new ObjectID(fileID),
|
||||
"metadata.owner": userID},
|
||||
"metadata.owner": new ObjectID(userID)},
|
||||
{"$unset": {"metadata.linkType": "", "metadata.link": ""}}) as FileInterface;
|
||||
|
||||
return file;
|
||||
@@ -42,7 +42,7 @@ class DbUtil {
|
||||
|
||||
const file = await conn.db.collection("fs.files")
|
||||
.findOneAndUpdate({"_id": new ObjectID(fileID),
|
||||
"metadata.owner": userID},
|
||||
"metadata.owner": new ObjectID(userID)},
|
||||
{"$set": {"metadata.linkType": "public", "metadata.link": token}}) as FileInterface
|
||||
|
||||
return file;
|
||||
@@ -60,7 +60,7 @@ class DbUtil {
|
||||
|
||||
const file = await conn.db.collection("fs.files")
|
||||
.findOneAndUpdate({"_id": new ObjectID(fileID),
|
||||
"metadata.owner": userID},
|
||||
"metadata.owner": new ObjectID(userID)},
|
||||
{"$set": {"metadata.linkType": "one", "metadata.link": token}}) as FileInterface;
|
||||
|
||||
return file;
|
||||
@@ -69,15 +69,21 @@ class DbUtil {
|
||||
getFileInfo = async(fileID: string, userID: string) => {
|
||||
|
||||
const file = await conn.db.collection("fs.files")
|
||||
.findOne({"metadata.owner": userID, "_id": new ObjectID(fileID)}) as FileInterface;
|
||||
.findOne({"metadata.owner": new ObjectID(userID), "_id": new ObjectID(fileID)}) as FileInterface;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
getQuickList = async(userID: string) => {
|
||||
getQuickList = async(userID: string, s3Enabled: boolean) => {
|
||||
|
||||
let query: any = {"metadata.owner": new ObjectID(userID)}
|
||||
|
||||
if (!s3Enabled){
|
||||
query = {...query, "metadata.personalFile": null}
|
||||
}
|
||||
|
||||
const fileList = await conn.db.collection("fs.files")
|
||||
.find({"metadata.owner": userID})
|
||||
.find(query)
|
||||
.sort({uploadDate: -1})
|
||||
.limit(10)
|
||||
.toArray() as FileInterface[];
|
||||
@@ -109,8 +115,10 @@ class DbUtil {
|
||||
|
||||
getFileSearchList = async(userID: string, searchQuery: RegExp) => {
|
||||
|
||||
let query:any = {"metadata.owner": new ObjectID(userID), "filename": searchQuery};
|
||||
|
||||
const fileList = await conn.db.collection("fs.files")
|
||||
.find({"metadata.owner": userID, "filename": searchQuery})
|
||||
.find(query)
|
||||
.limit(10)
|
||||
.toArray() as FileInterface[];
|
||||
|
||||
@@ -121,7 +129,7 @@ class DbUtil {
|
||||
|
||||
const file = await conn.db.collection("fs.files")
|
||||
.findOneAndUpdate({"_id": new ObjectID(fileID),
|
||||
"metadata.owner": userID}, {"$set": {"filename": title}}) as FileInterface;
|
||||
"metadata.owner": new ObjectID(userID)}, {"$set": {"filename": title}}) as FileInterface;
|
||||
|
||||
return file;
|
||||
}
|
||||
@@ -130,7 +138,7 @@ class DbUtil {
|
||||
|
||||
const file = await conn.db.collection("fs.files")
|
||||
.findOneAndUpdate({"_id": new ObjectID(fileID),
|
||||
"metadata.owner": userID}, {"$set": {"metadata.parent": parent, "metadata.parentList": parentList}})
|
||||
"metadata.owner": new ObjectID(userID)}, {"$set": {"metadata.parent": parent, "metadata.parentList": parentList}})
|
||||
|
||||
return file;
|
||||
}
|
||||
@@ -138,7 +146,7 @@ class DbUtil {
|
||||
getFileListByParent = async(userID: string, parentListString: string) => {
|
||||
|
||||
const fileList = await conn.db.collection("fs.files")
|
||||
.find({"metadata.owner": userID,
|
||||
.find({"metadata.owner": new ObjectID(userID),
|
||||
"metadata.parentList": {$regex : `.*${parentListString}.*`}}).toArray() as FileInterface[];
|
||||
|
||||
return fileList;
|
||||
@@ -147,7 +155,7 @@ class DbUtil {
|
||||
getFileListByOwner = async(userID: string) => {
|
||||
|
||||
const fileList = await conn.db.collection("fs.files")
|
||||
.find({"metadata.owner": userID}).toArray() as FileInterface[];
|
||||
.find({"metadata.owner": new ObjectID(userID)}).toArray() as FileInterface[];
|
||||
|
||||
return fileList;
|
||||
}
|
||||
@@ -158,4 +166,5 @@ class DbUtil {
|
||||
}
|
||||
}
|
||||
|
||||
export default DbUtil;
|
||||
export default DbUtil;
|
||||
module.exports = DbUtil;
|
||||
@@ -9,7 +9,9 @@ class DbUtil {
|
||||
|
||||
getFolderSearchList = async(userID: string, searchQuery: RegExp) => {
|
||||
|
||||
const folderList = await Folder.find({"owner": userID, "name": searchQuery}).limit(10) as FolderInterface[];
|
||||
let query:any = {"owner": userID, "name": searchQuery};
|
||||
|
||||
const folderList = await Folder.find(query).limit(10) as FolderInterface[];
|
||||
|
||||
return folderList;
|
||||
}
|
||||
@@ -21,17 +23,64 @@ class DbUtil {
|
||||
return folder;
|
||||
}
|
||||
|
||||
getFolderListByParent = async(userID: string, parent: string, sortBy: string) => {
|
||||
getFolderListByParent = async(userID: string, parent: string, sortBy: string, s3Enabled: boolean, type: string, storageType: string, itemType: string) => {
|
||||
|
||||
const folderList = await Folder.find({"owner": userID, "parent": parent})
|
||||
let query: any = {"owner": userID, "parent": parent};
|
||||
|
||||
if (!s3Enabled) {
|
||||
query = {...query, "personalFolder": null}
|
||||
}
|
||||
|
||||
if (type) {
|
||||
if (type === "mongo") {
|
||||
query = {...query, "personalFolder": null}
|
||||
} else if (type === "s3") {
|
||||
query = {...query, "personalFolder": true}
|
||||
}
|
||||
}
|
||||
|
||||
if (itemType) {
|
||||
if (itemType === "personal") query = {...query, "personalFolder": true}
|
||||
if (itemType === "nonpersonal") query = {...query, "personalFolder": null}
|
||||
}
|
||||
|
||||
const folderList = await Folder.find(query)
|
||||
.sort(sortBy) as FolderInterface[];
|
||||
|
||||
return folderList;
|
||||
}
|
||||
|
||||
getFolderListBySearch = async(userID: string, searchQuery: string, sortBy: string) => {
|
||||
getFolderListBySearch = async(userID: string, searchQuery: string, sortBy: string, type: string, parent: string, storageType: string, folderSearch: boolean, itemType: string, s3Enabled: boolean) => {
|
||||
|
||||
const folderList = await Folder.find({"name": searchQuery,"owner": userID})
|
||||
let query: any = {"name": searchQuery,"owner": userID};
|
||||
|
||||
if (type) {
|
||||
if (type === "mongo") {
|
||||
query = {...query, "personalFolder": null}
|
||||
} else {
|
||||
query = {...query, "personalFolder": true}
|
||||
}
|
||||
}
|
||||
|
||||
if (storageType === "s3") {
|
||||
query = {...query, "personalFolder": true}
|
||||
}
|
||||
|
||||
if (parent && (parent !== "/" || folderSearch)) {
|
||||
query = {...query, parent}
|
||||
}
|
||||
|
||||
if (!s3Enabled) {
|
||||
query = {...query, "personalFolder": null}
|
||||
}
|
||||
|
||||
if (itemType) {
|
||||
|
||||
if (itemType === "personal") query = {...query, "personalFolder": true}
|
||||
if (itemType === "nonpersonal") query = {...query, "personalFolder": null}
|
||||
}
|
||||
|
||||
const folderList = await Folder.find(query)
|
||||
.sort(sortBy) as FolderInterface[];
|
||||
|
||||
return folderList;
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
import {UserInterface} from "../../../models/user";
|
||||
import { google } from "googleapis";
|
||||
import getGoogleAuth from "../../../db/googleAuth";
|
||||
import createQueryGoogle, {googleQueryType} from "../../../utils/createQueryGoogle";
|
||||
|
||||
const fields = 'id, name, size, modifiedTime, hasThumbnail, parents, mimeType, thumbnailLink, webViewLink, shared';
|
||||
|
||||
class GoogleDbUtil {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
getList = async(query: googleQueryType, user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
|
||||
const limit = query.limit;
|
||||
|
||||
let parent = query.parent === "/" ? "root" : query.parent;
|
||||
|
||||
const {queryBuilder, orderBy} = createQueryGoogle(query, parent)
|
||||
|
||||
const previosPageToken = query.pageToken;
|
||||
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
const files = await drive.files.list({pageSize: limit, fields: `nextPageToken, files(${fields})`, q: queryBuilder, orderBy, pageToken: previosPageToken});
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
getFileInfo = async(id: string, user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
const file = await drive.files.get({fileId: id, fields: fields});
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
getQuickList = async(user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
let query = 'mimeType != "application/vnd.google-apps.folder" and trashed=false';
|
||||
|
||||
const files = await drive.files.list({pageSize: 10, fields: `nextPageToken, files(${fields})`, q: query});
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
getSuggestedList = async(searchQuery: string, user: UserInterface) => {
|
||||
|
||||
const driveQuery = `name contains "${searchQuery}" and mimeType != "application/vnd.google-apps.folder" and trashed=false`
|
||||
const driveQueryFolder = `name contains "${searchQuery}" and mimeType = "application/vnd.google-apps.folder" and trashed=false`
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
const files = await drive.files.list({pageSize: 10, fields: `nextPageToken, files(${fields})`, q: driveQuery});
|
||||
const folders = await drive.files.list({pageSize: 10, fields: `nextPageToken, files(${fields})`, q: driveQueryFolder});
|
||||
|
||||
return {
|
||||
files,
|
||||
folders
|
||||
}
|
||||
}
|
||||
|
||||
renameFile = async(fileID: string, title: string, user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
await drive.files.update({fileId: fileID, requestBody: {name:title}})
|
||||
}
|
||||
|
||||
removeFile = async(fileID: string, user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
await drive.files.delete({fileId:fileID});
|
||||
}
|
||||
|
||||
getDownloadFileMetadata = async(fileID: string, user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
const fileMetadata = await drive.files.get({fileId: fileID, fields: "*"});
|
||||
|
||||
return {fileMetadata, drive};
|
||||
}
|
||||
|
||||
moveFile = async(fileID: string, parentID: string, user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
const previousFile = await drive.files.get({
|
||||
fileId: fileID,
|
||||
fields: "*"
|
||||
})
|
||||
|
||||
const previousParent = previousFile.data.parents![0];
|
||||
|
||||
await drive.files.update({
|
||||
fileId: fileID,
|
||||
addParents: parentID,
|
||||
removeParents: previousParent,
|
||||
fields: fields
|
||||
})
|
||||
}
|
||||
|
||||
makeFilePublic = async(fileID: string, user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
await drive.permissions.create({
|
||||
requestBody: {
|
||||
type: "anyone",
|
||||
role: "reader"
|
||||
},
|
||||
fileId: fileID,
|
||||
fields: "*"
|
||||
})
|
||||
|
||||
const fileDetails = await drive.files.get({
|
||||
fileId: fileID,
|
||||
fields: fields
|
||||
})
|
||||
|
||||
const publicURL = fileDetails.data.webViewLink!;
|
||||
|
||||
return publicURL;
|
||||
}
|
||||
|
||||
removePublicLink = async(fileID: string, user: UserInterface) => {
|
||||
|
||||
const {fileMetadata, drive} = await this.getDownloadFileMetadata(fileID, user);
|
||||
|
||||
await drive.permissions.get({
|
||||
fileId: fileID,
|
||||
permissionId: fileMetadata.data.permissionIds![0]
|
||||
})
|
||||
|
||||
await drive.permissions.delete({
|
||||
fileId: fileID,
|
||||
permissionId: fileMetadata.data.permissionIds![0]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default GoogleDbUtil;
|
||||
@@ -0,0 +1,100 @@
|
||||
import {UserInterface} from "../../../models/user";
|
||||
import { google } from "googleapis";
|
||||
import getGoogleAuth from "../../../db/googleAuth";
|
||||
import {googleQueryType} from "../../../utils/createQueryGoogle";
|
||||
import createQueryGoogleFolder from "../../../utils/createQueryGoogleFolder";
|
||||
|
||||
const fields = 'id, name, createdTime, parents, mimeType'
|
||||
|
||||
class GoogleFolderUtils {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
getList = async(query: googleQueryType, user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
const limit = query.limit;
|
||||
|
||||
let parent = query.parent === "/" ? "root" : query.parent;
|
||||
|
||||
const {orderBy, queryBuilder} = createQueryGoogleFolder(query, parent);
|
||||
|
||||
const folders = await drive.files.list({pageSize: limit, fields: `files(${fields})`, q: queryBuilder, orderBy});
|
||||
|
||||
return folders;
|
||||
}
|
||||
|
||||
getInfo = async(id: string, user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
const folder = await drive.files.get({fileId: id, fields: fields});
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
renameFolder = async(folderID: string, title: string, user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
await drive.files.update({fileId: folderID, requestBody: {name:title}});
|
||||
}
|
||||
|
||||
removeFolder = async(folderID: string, user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
await drive.files.delete({fileId:folderID});
|
||||
}
|
||||
|
||||
uploadFolder = async(name: string, parent: string, user: UserInterface) => {
|
||||
|
||||
parent = parent === "/" ? "root" : parent;
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
const folderMetadata = {
|
||||
name,
|
||||
mimeType: 'application/vnd.google-apps.folder',
|
||||
parents: [parent]
|
||||
}
|
||||
|
||||
const createdFolder = await drive.files.create({
|
||||
requestBody: folderMetadata,
|
||||
fields: fields
|
||||
})
|
||||
|
||||
return createdFolder;
|
||||
}
|
||||
|
||||
moveFolder = async(fileID: string, parentID: string, user: UserInterface) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
const previousFile = await drive.files.get({
|
||||
fileId: fileID,
|
||||
fields: fields
|
||||
})
|
||||
|
||||
const previousParent = previousFile.data.parents![0];
|
||||
|
||||
await drive.files.update({
|
||||
fileId: fileID,
|
||||
addParents: parentID,
|
||||
removeParents: previousParent,
|
||||
fields: fields
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default GoogleFolderUtils;
|
||||
@@ -1,7 +1,9 @@
|
||||
export default {
|
||||
key: process.env.KEY,
|
||||
newKey: process.env.NEW_KEY,
|
||||
password: process.env.PASSWORD,
|
||||
passwordAccess: process.env.PASSWORD_ACCESS,
|
||||
passwordRefresh: process.env.PASSWORD_REFRESH,
|
||||
passwordCookie: process.env.PASSWORD_COOKIE,
|
||||
createAcctBlocked: process.env.BLOCK_CREATE_ACCOUNT,
|
||||
root: process.env.ROOT,
|
||||
url: process.env.URL,
|
||||
@@ -12,5 +14,34 @@ export default {
|
||||
s3Key: process.env.S3_KEY,
|
||||
s3Bucket: process.env.S3_BUCKET,
|
||||
useDocumentDB: process.env.USE_DOCUMENT_DB,
|
||||
documentDBBundle: process.env.DOCUMENT_DB_BUNDLE
|
||||
documentDBBundle: process.env.DOCUMENT_DB_BUNDLE,
|
||||
sendgridKey: process.env.SENDGRID_KEY,
|
||||
sendgridEmail: process.env.SENDGRID_EMAIL,
|
||||
remoteURL: process.env.REMOTE_URL,
|
||||
disableEmailVerification: process.env.DISABLE_EMAIL_VERIFICATION,
|
||||
secureCookies: process.env.SECURE_COOKIES
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
key: process.env.KEY,
|
||||
newKey: process.env.NEW_KEY,
|
||||
passwordAccess: process.env.PASSWORD_ACCESS,
|
||||
passwordRefresh: process.env.PASSWORD_REFRESH,
|
||||
passwordCookie: process.env.PASSWORD_COOKIE,
|
||||
createAcctBlocked: process.env.BLOCK_CREATE_ACCOUNT,
|
||||
root: process.env.ROOT,
|
||||
url: process.env.URL,
|
||||
mongoURL: process.env.MONGODB_URL,
|
||||
dbType: process.env.DB_TYPE,
|
||||
fsDirectory: process.env.FS_DIRECTORY,
|
||||
s3ID: process.env.S3_ID,
|
||||
s3Key: process.env.S3_KEY,
|
||||
s3Bucket: process.env.S3_BUCKET,
|
||||
useDocumentDB: process.env.USE_DOCUMENT_DB,
|
||||
documentDBBundle: process.env.DOCUMENT_DB_BUNDLE,
|
||||
sendgridKey: process.env.SENDGRID_KEY,
|
||||
sendgridEmail: process.env.SENDGRID_EMAIL,
|
||||
remoteURL: process.env.REMOTE_URL,
|
||||
disableEmailVerification: process.env.DISABLE_EMAIL_VERIFICATION,
|
||||
secureCookies: process.env.SECURE_COOKIES
|
||||
}
|
||||
@@ -20,4 +20,5 @@ const getEnvVariables = () => {
|
||||
}
|
||||
}
|
||||
|
||||
export default getEnvVariables;
|
||||
export default getEnvVariables;
|
||||
module.exports = getEnvVariables
|
||||
@@ -1,38 +1,43 @@
|
||||
import {Router} from "express";
|
||||
import auth from "../middleware/auth";
|
||||
import tempAuth from "../middleware/tempAuth";
|
||||
import tempAuthVideo from "../middleware/tempAuthVideo";
|
||||
import FileController from "../controllers/file";
|
||||
import env from "../enviroment/env";
|
||||
import MongoService from "../services/ChunkService/MongoService";
|
||||
import FileSystemService from "../services/ChunkService/FileSystemService";
|
||||
import S3Service from "../services/ChunkService/S3Service";
|
||||
import ChunkInterface from "../services/ChunkService/utils/ChunkInterface";
|
||||
import authFullUser from "../middleware/authFullUser";
|
||||
import authStreamVideo from "../middleware/authStreamVideo";
|
||||
|
||||
let fileController: FileController;
|
||||
let chunkService: ChunkInterface;
|
||||
|
||||
if (env.dbType === "mongo") {
|
||||
|
||||
const mongoService = new MongoService();
|
||||
chunkService = mongoService;
|
||||
fileController = new FileController(mongoService);
|
||||
|
||||
} else if (env.dbType === "fs") {
|
||||
|
||||
const fileSystemService = new FileSystemService();
|
||||
chunkService = fileSystemService
|
||||
fileController = new FileController(fileSystemService);
|
||||
|
||||
} else {
|
||||
|
||||
const s3Service = new S3Service();
|
||||
chunkService = s3Service;
|
||||
fileController = new FileController(s3Service);
|
||||
}
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post("/file-service/upload", auth, fileController.uploadFile);
|
||||
router.post("/file-service/upload", authFullUser, fileController.uploadFile);
|
||||
|
||||
router.get("/file-service/thumbnail/:id", auth, fileController.getThumbnail);
|
||||
router.get("/file-service/thumbnail/:id", authFullUser, fileController.getThumbnail);
|
||||
|
||||
router.get("/file-service/full-thumbnail/:id", auth, fileController.getFullThumbnail);
|
||||
router.get("/file-service/full-thumbnail/:id", authFullUser, fileController.getFullThumbnail);
|
||||
|
||||
router.get("/file-service/public/download/:id/:tempToken", fileController.getPublicDownload);
|
||||
|
||||
@@ -44,17 +49,17 @@ 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/access-token-stream-video", authFullUser, fileController.getAccessTokenStreamVideo)
|
||||
|
||||
router.get("/file-service/download/get-token-video", auth, fileController.getDownloadTokenVideo);
|
||||
router.get("/file-service/stream-video/:id", authStreamVideo, fileController.streamVideo);
|
||||
|
||||
router.get("/file-service/stream-video/:id/:tempToken/:uuid", tempAuthVideo, fileController.streamVideo);
|
||||
router.delete("/file-service/remove-stream-video-token", authStreamVideo, fileController.removeStreamVideoAccessToken);
|
||||
|
||||
router.get("/file-service/download/:id/:tempToken", tempAuth, fileController.downloadFile);
|
||||
router.get("/file-service/download/:id", authFullUser, 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-public/:id", authFullUser, fileController.makePublic);
|
||||
|
||||
router.patch("/file-service/make-one/:id", auth, fileController.makeOneTimePublic);
|
||||
|
||||
@@ -64,8 +69,18 @@ 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/:uuid", auth, fileController.removeTempToken);
|
||||
router.delete("/file-service/remove/token-video/:id", auth, fileController.removeTempToken);
|
||||
|
||||
router.delete("/file-service/remove", auth, fileController.deleteFile);
|
||||
|
||||
export default router;
|
||||
router.post("/file-service/send-share-email", auth, fileController.sendEmailShare);
|
||||
|
||||
export default router;
|
||||
|
||||
// NO longer needed left for reference
|
||||
|
||||
//router.delete("/file-service/remove/token-video/:tempToken/:uuid", auth, fileController.removeTempToken);
|
||||
//router.get("/file-service/stream-video/:id/:tempToken/:uuid", auth, fileController.streamVideo);
|
||||
//router.get("/file-service/stream-video/:id", auth, fileController.streamVideo);
|
||||
//router.get("/file-service/download/get-token", authFullUser, fileController.getDownloadToken);
|
||||
//router.get("/file-service/download/get-token-video", auth, fileController.getDownloadTokenVideo);
|
||||
@@ -42,4 +42,10 @@ router.patch("/folder-service/rename", auth, folderController.renameFolder);
|
||||
|
||||
router.patch("/folder-service/move", auth, folderController.moveFolder);
|
||||
|
||||
router.get("/folder-service/subfolder-list-full", auth, folderController.getSubfolderFullList);
|
||||
|
||||
// Personal Folder
|
||||
|
||||
router.delete("/folder-service-personal/remove", auth, folderController.deletePersonalFolder);
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,42 @@
|
||||
import {Router} from "express";
|
||||
import GoogleFileController from "../controllers/googleFile";
|
||||
import authFullUser from "../middleware/authFullUser";
|
||||
import authStreamVideo from "../middleware/authStreamVideo";
|
||||
|
||||
const googleController = new GoogleFileController();
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/file-service-google/list", authFullUser, googleController.getList);
|
||||
|
||||
router.get("/file-service-google-mongo/list", authFullUser, googleController.getMongoGoogleList);
|
||||
|
||||
router.get("/file-service-google/info/:id", authFullUser, googleController.getFileInfo);
|
||||
|
||||
router.get("/file-service-google-mongo/quick-list", authFullUser, googleController.getGoogleMongoQuickList);
|
||||
|
||||
router.get("/file-service-google-mongo/suggested-list", authFullUser, googleController.getGoogleMongoSuggestedList);
|
||||
|
||||
router.patch("/file-service-google/rename", authFullUser, googleController.renameFile);
|
||||
|
||||
router.delete("/file-service-google/remove", authFullUser, googleController.removeFile);
|
||||
|
||||
router.get("/file-service-google/download/:id", authFullUser, googleController.downloadFile);
|
||||
|
||||
router.get("/file-service-google-doc/download/:id", authFullUser, googleController.downloadDoc);
|
||||
|
||||
router.get("/file-service-google/thumbnail/:id", authFullUser, googleController.getThumbnail);
|
||||
|
||||
router.get("/file-service-google/full-thumbnail/:id", authFullUser, googleController.getFulllThumbnail);
|
||||
|
||||
router.get("/file-service-google/stream-video/:id", authStreamVideo, googleController.streamVideo);
|
||||
|
||||
router.post("/file-service-google/upload", authFullUser, googleController.uploadFile);
|
||||
|
||||
router.patch("/file-service-google/move", authFullUser, googleController.moveFile);
|
||||
|
||||
router.patch("/file-service-google/make-public/:id", authFullUser, googleController.makeFilePublic);
|
||||
|
||||
router.delete("/file-service-google/remove-link/:id", authFullUser, googleController.removePublicLink);
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,27 @@
|
||||
import {Router} from "express";
|
||||
import GoogleFolderController from "../controllers/googleFolder";
|
||||
import authFullUser from "../middleware/authFullUser";
|
||||
|
||||
const googleFolderController = new GoogleFolderController();
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/folder-service-google/list", authFullUser, googleFolderController.getList);
|
||||
|
||||
router.get("/folder-service-google-mongo/list", authFullUser, googleFolderController.getGoogleMongoList);
|
||||
|
||||
router.get("/folder-service-google/info/:id", authFullUser, googleFolderController.getInfo);
|
||||
|
||||
router.get("/folder-service-google/subfolder-list", authFullUser, googleFolderController.getSubFolderList);
|
||||
|
||||
router.get("/folder-service-google/subfolder-list-full", authFullUser, googleFolderController.getSubfolderFullList);
|
||||
|
||||
router.patch("/folder-service-google/rename", authFullUser, googleFolderController.renameFolder);
|
||||
|
||||
router.delete("/folder-service-google/remove", authFullUser,googleFolderController.removeFolder);
|
||||
|
||||
router.post("/folder-service-google/upload", authFullUser, googleFolderController.upload);
|
||||
|
||||
router.patch("/folder-service-google/move", authFullUser, googleFolderController.moveFolder);
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,26 @@
|
||||
import {Router} from "express";
|
||||
import auth from "../middleware/auth";
|
||||
import PersonalFileController from "../controllers/personalFile";
|
||||
import authFullUser from "../middleware/authFullUser";
|
||||
import authStreamVideo from "../middleware/authStreamVideo";
|
||||
|
||||
const personalFileController = new PersonalFileController();
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post("/file-service-personal/upload", authFullUser, personalFileController.uploadPersonalFile);
|
||||
|
||||
router.get("/file-service-personal/download/:id", authFullUser, personalFileController.downloadPersonalFile);
|
||||
|
||||
router.get("/file-service-personal/thumbnail/:id", authFullUser, personalFileController.getPersonalThumbnail);
|
||||
|
||||
router.get("/file-service-personal/full-thumbnail/:id", authFullUser, personalFileController.getFullPersonalThumbnail);
|
||||
|
||||
router.get("/file-service-personal/stream-video/:id", authStreamVideo, personalFileController.streamPersonalVideo);
|
||||
|
||||
router.get("/file-service-personal/public/download/:id/:tempToken", personalFileController.getPublicPersonalDownload);
|
||||
|
||||
router.delete("/file-service-personal/remove", auth, personalFileController.deletePersonalFile);
|
||||
|
||||
|
||||
export default router;
|
||||
@@ -6,6 +6,8 @@ const storageController = new StorageController();
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/storage-service/info", auth, storageController.getStorageInfo);
|
||||
// No longer needed left for reference
|
||||
|
||||
// router.get("/storage-service/info", auth, storageController.getStorageInfo);
|
||||
|
||||
export default router;
|
||||
@@ -1,21 +1,40 @@
|
||||
import { Router } from "express";
|
||||
import auth from "../middleware/auth";
|
||||
import authNoEmailVerification from "../middleware/authNoEmailVerificication"
|
||||
import UserController from "../controllers/user";
|
||||
import authRefresh from "../middleware/authRefresh";
|
||||
import authLogout from "../middleware/authLogout";
|
||||
|
||||
const userController = new UserController();
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/user-service/user", auth, userController.getUser);
|
||||
router.get("/user-service/user", authNoEmailVerification, userController.getUser);
|
||||
|
||||
router.patch("/user-service/refresh-storage-size", auth, userController.refreshStorageSize);
|
||||
|
||||
router.get("/user-service/user-detailed", auth, userController.getUserDetailed);
|
||||
|
||||
router.post("/user-service/login", userController.login);
|
||||
|
||||
router.post("/user-service/logout", auth, userController.logout);
|
||||
router.post("/user-service/logout", authLogout, userController.logout);
|
||||
|
||||
router.post("/user-service/logout-all", auth, userController.logoutAll);
|
||||
router.post("/user-service/logout-all", authLogout, userController.logoutAll);
|
||||
|
||||
router.post("/user-service/create", userController.createUser);
|
||||
|
||||
router.post("/user-service/change-password", auth, userController.changePassword);
|
||||
|
||||
router.post("/user-service/verify-email", userController.verifyEmail);
|
||||
|
||||
router.post("/user-service/resend-verify-email", authNoEmailVerification, userController.resendVerifyEmail);
|
||||
|
||||
router.post("/user-service/send-password-reset", userController.sendPasswordReset);
|
||||
|
||||
router.post("/user-service/reset-password", userController.resetPassword);
|
||||
|
||||
router.patch("/user-service/add-name", auth, userController.addName);
|
||||
|
||||
router.post("/user-service/get-token", authRefresh, userController.getToken);
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Router } from "express";
|
||||
import UserGoogleController from "../controllers/userGoogle";
|
||||
import authFullUser from "../middleware/authFullUser";
|
||||
|
||||
const userGoogleController = new UserGoogleController();
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post("/user-service/create-google-storage-url", authFullUser, userGoogleController.createGoogleStorageURL);
|
||||
|
||||
router.post("/user-service/add-google-storage", authFullUser, userGoogleController.addGoogleStorage);
|
||||
|
||||
router.delete("/user-service/remove-google-storage", authFullUser, userGoogleController.removeGoogleStorage);
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Router } from "express";
|
||||
import auth from "../middleware/auth";
|
||||
import UserPersonalController from "../controllers/userPersonal";
|
||||
import authFullUser from "../middleware/authFullUser";
|
||||
|
||||
const userPersonalController = new UserPersonalController();
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/user-service/download-personal-file-list", auth, userPersonalController.downloadPersonalFileList);
|
||||
|
||||
router.post("/user-service/upload-personal-file-list", auth, userPersonalController.uploadPersonalFileList);
|
||||
|
||||
router.post("/user-service/add-s3-storage", authFullUser, userPersonalController.addS3Storage);
|
||||
|
||||
router.delete("/user-service/remove-s3-storage", authFullUser, userPersonalController.removeS3Storage);
|
||||
|
||||
router.delete("/user-service/remove-s3-metadata", auth, userPersonalController.removeS3Metadata);
|
||||
|
||||
export default router;
|
||||
@@ -1,4 +1,3 @@
|
||||
const prompt = require('password-prompt')
|
||||
import env from "../enviroment/env";
|
||||
import crypto from "crypto";
|
||||
import getWebUIKey from "./getWebUIKey";
|
||||
|
||||
@@ -40,7 +40,7 @@ const getWebUIKey = () => {
|
||||
|
||||
const server = http.createServer(app) as any;
|
||||
|
||||
server.listen(port, url, () => {
|
||||
server.listen(port, () => {
|
||||
|
||||
console.log(`\nPlease navigate to http://localhost:${port} to enter encryption key\n`)
|
||||
|
||||
|
||||
@@ -1,61 +1,54 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
import User, {UserInterface} from "../models/user";
|
||||
import env from "../enviroment/env";
|
||||
import {Request, Response, NextFunction} from "express";
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: UserInterface,
|
||||
user?: userAccessType,
|
||||
token?: string,
|
||||
encryptedToken?: string,
|
||||
}
|
||||
|
||||
type jwtType = {
|
||||
iv: Buffer,
|
||||
user: userAccessType
|
||||
}
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
admin: boolean,
|
||||
botChecked: boolean,
|
||||
username: string,
|
||||
}
|
||||
|
||||
const auth = async(req: RequestType, res: Response, next: NextFunction) => {
|
||||
|
||||
try {
|
||||
|
||||
const token = req.header("Authorization")!.replace("Bearer ", "");
|
||||
const accessToken = req.cookies["access-token"];
|
||||
|
||||
const decoded = jwt.verify(token, env.password!) as jwtType;
|
||||
if (!accessToken) throw new Error("No Access Token");
|
||||
|
||||
const iv = decoded.iv;
|
||||
|
||||
const user = await User.findOne({_id: decoded._id}) as UserInterface;
|
||||
const encrpytionKey = user.getEncryptionKey();
|
||||
|
||||
const encryptedToken = user.encryptToken(token, encrpytionKey, iv);
|
||||
const decoded = jwt.verify(accessToken, env.passwordAccess!) as jwtType;
|
||||
|
||||
let tokenFound = false;
|
||||
for (let i = 0; i < user.tokens.length; i++) {
|
||||
const user = decoded.user;
|
||||
|
||||
const currentToken = user.tokens[i].token;
|
||||
if (!user) throw new Error("No User");
|
||||
if (!user.emailVerified && !env.disableEmailVerification) throw new Error("Email Not Verified")
|
||||
|
||||
if (currentToken === encryptedToken) {
|
||||
tokenFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
req.user = user;
|
||||
|
||||
if (!user || !tokenFound) {
|
||||
|
||||
throw new Error("User not found")
|
||||
|
||||
} else {
|
||||
|
||||
req.token = token;
|
||||
req.encryptedToken = encryptedToken
|
||||
req.user = user;
|
||||
next();
|
||||
}
|
||||
next();
|
||||
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
res.status(401).send({error: "Error Authenticating"})
|
||||
|
||||
if (e.message !== "No Access Token" &&
|
||||
e.message !== "No User" &&
|
||||
e.message !== "Email Not Verified") console.log("\nAuthorization Middleware Error:", e.message);
|
||||
|
||||
res.status(401).send("Error Authenticating");
|
||||
}
|
||||
}
|
||||
|
||||
export default auth;
|
||||
export default auth;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
import User, {UserInterface} from "../models/user";
|
||||
import env from "../enviroment/env";
|
||||
import {Request, Response, NextFunction} from "express";
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: UserInterface,
|
||||
token?: string,
|
||||
encryptedToken?: string,
|
||||
}
|
||||
|
||||
type jwtType = {
|
||||
iv: Buffer,
|
||||
user: userAccessType
|
||||
}
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
admin: boolean,
|
||||
botChecked: boolean,
|
||||
username: string,
|
||||
}
|
||||
|
||||
const authFullUser = async(req: RequestType, res: Response, next: NextFunction) => {
|
||||
|
||||
try {
|
||||
|
||||
const accessToken = req.cookies["access-token"];
|
||||
|
||||
if (!accessToken) throw new Error("No Access Token");
|
||||
|
||||
const decoded = jwt.verify(accessToken, env.passwordAccess!) as jwtType;
|
||||
|
||||
const user = decoded.user;
|
||||
|
||||
if (!user) throw new Error("No User");
|
||||
if (!user.emailVerified && !env.disableEmailVerification) throw new Error("Email Not Verified")
|
||||
|
||||
const fullUser = await User.findById(user._id);
|
||||
|
||||
if (!fullUser) throw new Error("No User");
|
||||
|
||||
req.user = fullUser;
|
||||
|
||||
next();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
if (e.message !== "No Access Token" &&
|
||||
e.message !== "No User" &&
|
||||
e.message !== "Email Not Verified") console.log("\nAuthorization Full User Middleware Error:", e.message);
|
||||
|
||||
res.status(401).send("Error Authenticating");
|
||||
}
|
||||
}
|
||||
|
||||
export default authFullUser;
|
||||
@@ -0,0 +1,52 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
import env from "../enviroment/env";
|
||||
import {Request, Response, NextFunction} from "express";
|
||||
import { createLogoutCookie } from "../cookies/createCookies";
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: userAccessType,
|
||||
token?: string,
|
||||
encryptedToken?: string,
|
||||
}
|
||||
|
||||
type jwtType = {
|
||||
iv: Buffer,
|
||||
user: userAccessType
|
||||
}
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
botChecked: boolean,
|
||||
}
|
||||
|
||||
const auth = async(req: RequestType, res: Response, next: NextFunction) => {
|
||||
|
||||
try {
|
||||
|
||||
const accessToken = req.cookies["access-token"];
|
||||
|
||||
if (!accessToken) throw new Error("No Access Token");
|
||||
|
||||
const decoded = jwt.verify(accessToken, env.passwordAccess!) as jwtType;
|
||||
|
||||
const user = decoded.user;
|
||||
|
||||
if (!user) throw new Error("No User");
|
||||
|
||||
req.user = user;
|
||||
|
||||
next();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
if (e.message !== "No Access Token" &&
|
||||
e.message !== "No User") console.log("\nAuthorization Logout Middleware Error:", e.message);
|
||||
|
||||
createLogoutCookie(res);
|
||||
return res.status(401).send("Error Authenticating");
|
||||
}
|
||||
}
|
||||
|
||||
export default auth;
|
||||
@@ -0,0 +1,57 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
import User, {UserInterface} from "../models/user";
|
||||
import env from "../enviroment/env";
|
||||
import {Request, Response, NextFunction} from "express";
|
||||
import userUpdateCheck from "../utils/userUpdateCheck";
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: userAccessType,
|
||||
token?: string,
|
||||
encryptedToken?: string,
|
||||
}
|
||||
|
||||
type jwtType = {
|
||||
iv: Buffer,
|
||||
user: userAccessType
|
||||
}
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
botChecked: boolean,
|
||||
}
|
||||
|
||||
const auth = async(req: RequestType, res: Response, next: NextFunction) => {
|
||||
|
||||
try {
|
||||
|
||||
const accessToken = req.cookies["access-token"];
|
||||
|
||||
if (!accessToken) throw new Error("No Access Token");
|
||||
|
||||
const decoded = jwt.verify(accessToken, env.passwordAccess!) as jwtType;
|
||||
|
||||
let user = decoded.user;
|
||||
|
||||
if (!user) throw new Error("No User");
|
||||
|
||||
if (!user.emailVerified && !env.disableEmailVerification) {
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
user = await userUpdateCheck(res, user._id, currentUUID);
|
||||
}
|
||||
|
||||
req.user = user;
|
||||
|
||||
next();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
if (e.message !== "No Access Token" &&
|
||||
e.message !== "No User") console.log("\nAuthorization No Email Verification Middleware Error:", e.message);
|
||||
|
||||
return res.status(401).send("Error Authenticating");
|
||||
}
|
||||
}
|
||||
|
||||
export default auth;
|
||||
@@ -0,0 +1,92 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
import User, {UserInterface} from "../models/user";
|
||||
import env from "../enviroment/env";
|
||||
import {Request, Response, NextFunction} from "express";
|
||||
import { ObjectID } from "mongodb";
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: UserInterface,
|
||||
token?: string,
|
||||
encryptedToken?: string,
|
||||
}
|
||||
|
||||
type jwtType = {
|
||||
iv: Buffer,
|
||||
_id: string,
|
||||
time: number
|
||||
}
|
||||
|
||||
const removeOldTokens = async(userID: string, uuid: string | undefined, oldTime: number) => {
|
||||
|
||||
try {
|
||||
|
||||
const minusTime = oldTime - (1000 * 60 * 60);
|
||||
//const minusTime = oldTime - (1000);
|
||||
|
||||
uuid = uuid ? uuid : "unknown";
|
||||
|
||||
if (uuid === "unknown") return;
|
||||
|
||||
await User.updateOne({_id: userID}, {$pull: {tokens: {uuid, time: {$lt: minusTime}}}})
|
||||
|
||||
} catch (e) {
|
||||
console.log("cannot remove old tokens", e);
|
||||
}
|
||||
}
|
||||
|
||||
const authRefresh = async(req: RequestType, res: Response, next: NextFunction) => {
|
||||
|
||||
try {
|
||||
|
||||
const refreshToken = req.cookies["refresh-token"];
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
|
||||
if (!refreshToken) throw new Error("No Refresh Token");
|
||||
|
||||
const decoded = jwt.verify(refreshToken, env.passwordRefresh!) as jwtType;
|
||||
|
||||
const time = decoded.time;
|
||||
|
||||
const user = await User.findById(new ObjectID(decoded._id));
|
||||
|
||||
if (!user) throw new Error("No User");
|
||||
|
||||
const encrpytionKey = user.getEncryptionKey();
|
||||
const encryptedToken = user.encryptToken(refreshToken, encrpytionKey, decoded.iv);
|
||||
|
||||
let tokenFound = false;
|
||||
|
||||
for (let i = 0; i < user.tokens.length; i++) {
|
||||
|
||||
const currentEncryptedToken = user.tokens[i].token;
|
||||
|
||||
if (currentEncryptedToken === encryptedToken) {
|
||||
|
||||
tokenFound = true;
|
||||
removeOldTokens(user._id, currentUUID, time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tokenFound) {
|
||||
console.log("token not found", encryptedToken);
|
||||
console.log("token list", user.tokens);
|
||||
}
|
||||
|
||||
if (!tokenFound) throw new Error("Refresh Token Not Found");
|
||||
|
||||
req.user = user;
|
||||
|
||||
next();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
if (e.message !== "No Refresh Token" &&
|
||||
e.message !== "No User" &&
|
||||
e.message !== "Refresh Token Not Found") console.log("\nAuthorization Refresh Middleware Error:", e.message);
|
||||
|
||||
res.status(401).send("Error Refreshing Token");
|
||||
}
|
||||
}
|
||||
|
||||
export default authRefresh;
|
||||
@@ -0,0 +1,89 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
import User, {UserInterface} from "../models/user";
|
||||
import env from "../enviroment/env";
|
||||
import {Request, Response, NextFunction} from "express";
|
||||
import { ObjectID } from "mongodb";
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: UserInterface,
|
||||
token?: string,
|
||||
encryptedToken?: string,
|
||||
accessTokenStreamVideo?: string
|
||||
}
|
||||
|
||||
type jwtType = {
|
||||
iv: Buffer,
|
||||
_id: string,
|
||||
time: number
|
||||
}
|
||||
|
||||
const removeOldTokens = async(userID: string, uuid: string | undefined, oldTime: number) => {
|
||||
|
||||
try {
|
||||
|
||||
const minusTime = oldTime - (60 * 1000 * 60 * 24);
|
||||
|
||||
uuid = uuid ? uuid : "unknown";
|
||||
|
||||
if (uuid === "unknown") return;
|
||||
|
||||
await User.updateOne({_id: userID}, {$pull: {tempTokens: {uuid, time: {$lt: minusTime}}}})
|
||||
|
||||
} catch (e) {
|
||||
console.log("cannot remove old tokens", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const authStreamVideo = async(req: RequestType, res: Response, next: NextFunction) => {
|
||||
|
||||
try {
|
||||
|
||||
const accessTokenStreamVideo = req.cookies["video-access-token"];
|
||||
const currentUUID = req.headers.uuid as string;
|
||||
|
||||
if (!accessTokenStreamVideo) throw new Error("No Access Token");
|
||||
|
||||
const decoded = jwt.verify(accessTokenStreamVideo, env.passwordAccess!) as jwtType;
|
||||
|
||||
const time = decoded.time;
|
||||
|
||||
const user = await User.findById(new ObjectID(decoded._id));
|
||||
|
||||
if (!user) throw new Error("No User");
|
||||
|
||||
const encrpytionKey = user.getEncryptionKey();
|
||||
const encryptedToken = user.encryptToken(accessTokenStreamVideo, encrpytionKey, decoded.iv);
|
||||
|
||||
let tokenFound = false;
|
||||
|
||||
for (let i = 0; i < user.tempTokens.length; i++) {
|
||||
|
||||
const currentEncryptedToken = user.tempTokens[i].token;
|
||||
|
||||
if (currentEncryptedToken === encryptedToken) {
|
||||
|
||||
tokenFound = true;
|
||||
removeOldTokens(user._id, currentUUID, time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tokenFound) throw new Error("Access Token Not Found");
|
||||
|
||||
req.user = user;
|
||||
req.accessTokenStreamVideo = encryptedToken;
|
||||
|
||||
next();
|
||||
|
||||
} catch (e) {
|
||||
|
||||
if (e.message !== "No Access Token" &&
|
||||
e.message !== "No User" &&
|
||||
e.message !== "Access Token Not Found") console.log("\nAuthorization Stream Video Middleware Error:", e.message);
|
||||
|
||||
res.status(401).send("Error Authenticating");
|
||||
}
|
||||
}
|
||||
|
||||
export default authStreamVideo;
|
||||
@@ -1,70 +1,70 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
import User, {UserInterface} from "../models/user";
|
||||
import env from "../enviroment/env";
|
||||
import {Request, Response, NextFunction} from "express";
|
||||
// import jwt from "jsonwebtoken";
|
||||
// import User, {UserInterface} from "../models/user";
|
||||
// import env from "../enviroment/env";
|
||||
// import {Request, Response, NextFunction} from "express";
|
||||
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: UserInterface,
|
||||
auth?: boolean,
|
||||
encryptedTempToken?: string,
|
||||
}
|
||||
// interface RequestType extends Request {
|
||||
// user?: UserInterface,
|
||||
// auth?: boolean,
|
||||
// encryptedTempToken?: string,
|
||||
// }
|
||||
|
||||
type jwtType = {
|
||||
iv: Buffer,
|
||||
_id: string,
|
||||
}
|
||||
// type jwtType = {
|
||||
// iv: Buffer,
|
||||
// _id: string,
|
||||
// }
|
||||
|
||||
const tempAuth = async(req: RequestType, res: Response, next: NextFunction) => {
|
||||
// const tempAuth = async(req: RequestType, res: Response, next: NextFunction) => {
|
||||
|
||||
try {
|
||||
// try {
|
||||
|
||||
const token = req.params.tempToken;
|
||||
// const token = req.params.tempToken;
|
||||
|
||||
const decoded = jwt.verify(token, env.password!) as jwtType;
|
||||
// const decoded = jwt.verify(token, env.passwordAccess!) as jwtType;
|
||||
|
||||
const iv = decoded.iv;
|
||||
// const iv = decoded.iv;
|
||||
|
||||
const user = await User.findOne({_id: decoded._id}) as UserInterface;
|
||||
const encrpytionKey = user.getEncryptionKey();
|
||||
// const user = await User.findOne({_id: decoded._id}) as UserInterface;
|
||||
// const encrpytionKey = user.getEncryptionKey();
|
||||
|
||||
const encryptedToken = user.encryptToken(token, encrpytionKey, iv);
|
||||
// const encryptedToken = user.encryptToken(token, encrpytionKey, iv);
|
||||
|
||||
let tokenFound = false;
|
||||
for (let i = 0; i < user.tempTokens.length; i++) {
|
||||
// let tokenFound = false;
|
||||
// for (let i = 0; i < user.tempTokens.length; i++) {
|
||||
|
||||
const currentToken = user.tempTokens[i].token;
|
||||
// const currentToken = user.tempTokens[i].token;
|
||||
|
||||
if (currentToken === encryptedToken) {
|
||||
tokenFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if (currentToken === encryptedToken) {
|
||||
// tokenFound = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (!user || !tokenFound) {
|
||||
// if (!user || !tokenFound) {
|
||||
|
||||
throw new Error("User Not Found")
|
||||
// throw new Error("User Not Found")
|
||||
|
||||
} else {
|
||||
// } else {
|
||||
|
||||
user.tempTokens = user.tempTokens.filter((filterToken) => {
|
||||
// user.tempTokens = user.tempTokens.filter((filterToken) => {
|
||||
|
||||
return filterToken.token !== encryptedToken
|
||||
})
|
||||
// return filterToken.token !== encryptedToken
|
||||
// })
|
||||
|
||||
await user.save();
|
||||
// await user.save();
|
||||
|
||||
req.user = user;
|
||||
req.auth = true;
|
||||
req.encryptedTempToken = encryptedToken;
|
||||
// req.user = user;
|
||||
// req.auth = true;
|
||||
// req.encryptedTempToken = encryptedToken;
|
||||
|
||||
next();
|
||||
}
|
||||
// next();
|
||||
// }
|
||||
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
res.status(401).send();
|
||||
}
|
||||
}
|
||||
// } catch (e) {
|
||||
// console.log(e);
|
||||
// res.status(401).send();
|
||||
// }
|
||||
// }
|
||||
|
||||
export default tempAuth;
|
||||
// export default tempAuth;
|
||||
@@ -1,70 +1,70 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
import User, {UserInterface} from "../models/user";
|
||||
import env from "../enviroment/env";
|
||||
import {Request, Response, NextFunction} from "express";
|
||||
// import jwt from "jsonwebtoken";
|
||||
// import User, {UserInterface} from "../models/user";
|
||||
// import env from "../enviroment/env";
|
||||
// import {Request, Response, NextFunction} from "express";
|
||||
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: UserInterface,
|
||||
auth?: boolean,
|
||||
encryptedTempToken?: string,
|
||||
}
|
||||
// interface RequestType extends Request {
|
||||
// user?: UserInterface,
|
||||
// auth?: boolean,
|
||||
// encryptedTempToken?: string,
|
||||
// }
|
||||
|
||||
type jwtType = {
|
||||
iv: Buffer,
|
||||
_id: string,
|
||||
cookie: string
|
||||
}
|
||||
// type jwtType = {
|
||||
// iv: Buffer,
|
||||
// _id: string,
|
||||
// cookie: string
|
||||
// }
|
||||
|
||||
const tempAuthVideo = async(req: RequestType, res: Response, next: NextFunction) => {
|
||||
// const tempAuthVideo = async(req: RequestType, res: Response, next: NextFunction) => {
|
||||
|
||||
try {
|
||||
// try {
|
||||
|
||||
const token = req.params.tempToken;
|
||||
// const token = req.params.tempToken;
|
||||
|
||||
const decoded = jwt.verify(token, env.password!) as jwtType;
|
||||
// const decoded = jwt.verify(token, env.passwordAccess!) as jwtType;
|
||||
|
||||
const iv = decoded.iv;
|
||||
// const iv = decoded.iv;
|
||||
|
||||
if (req.params.uuid !== decoded.cookie) {
|
||||
// if (req.params.uuid !== decoded.cookie) {
|
||||
|
||||
throw new Error("Cookie mismatch")
|
||||
}
|
||||
// throw new Error("Cookie mismatch")
|
||||
// }
|
||||
|
||||
const user = await User.findOne({_id: decoded._id}) as UserInterface;
|
||||
const encrpytionKey = user.getEncryptionKey();
|
||||
// const user = await User.findOne({_id: decoded._id}) as UserInterface;
|
||||
// const encrpytionKey = user.getEncryptionKey();
|
||||
|
||||
const encryptedToken = user.encryptToken(token, encrpytionKey, iv);
|
||||
// const encryptedToken = user.encryptToken(token, encrpytionKey, iv);
|
||||
|
||||
let tokenFound = false;
|
||||
for (let i = 0; i < user.tempTokens.length; i++) {
|
||||
// let tokenFound = false;
|
||||
// for (let i = 0; i < user.tempTokens.length; i++) {
|
||||
|
||||
const currentToken = user.tempTokens[i].token;
|
||||
// const currentToken = user.tempTokens[i].token;
|
||||
|
||||
if (currentToken === encryptedToken) {
|
||||
tokenFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if (currentToken === encryptedToken) {
|
||||
// tokenFound = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (!user || !tokenFound) {
|
||||
// if (!user || !tokenFound) {
|
||||
|
||||
throw new Error("User not found");
|
||||
// throw new Error("User not found");
|
||||
|
||||
} else {
|
||||
// } else {
|
||||
|
||||
await user.save();
|
||||
// await user.save();
|
||||
|
||||
req.user = user;
|
||||
req.auth = true;
|
||||
req.encryptedTempToken = encryptedToken;
|
||||
next();
|
||||
}
|
||||
// req.user = user;
|
||||
// req.auth = true;
|
||||
// req.encryptedTempToken = encryptedToken;
|
||||
// next();
|
||||
// }
|
||||
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
res.status(401).send();
|
||||
}
|
||||
}
|
||||
// } catch (e) {
|
||||
// console.log(e);
|
||||
// res.status(401).send();
|
||||
// }
|
||||
// }
|
||||
|
||||
export default tempAuthVideo;
|
||||
// export default tempAuthVideo;
|
||||
@@ -1,5 +1,5 @@
|
||||
import mongoose, {Document} from "mongoose";
|
||||
import { Binary } from "mongodb";
|
||||
import { Binary, ObjectID } from "mongodb";
|
||||
|
||||
const fileSchema = new mongoose.Schema({
|
||||
|
||||
@@ -53,6 +53,7 @@ const fileSchema = new mongoose.Schema({
|
||||
link: String,
|
||||
filePath: String,
|
||||
s3ID: String,
|
||||
personalFile: Boolean,
|
||||
|
||||
},
|
||||
required: true
|
||||
@@ -67,7 +68,7 @@ export interface FileInterface extends Document {
|
||||
filename: string,
|
||||
lastErrorObject: {updatedExisting: any}
|
||||
metadata: {
|
||||
owner: string,
|
||||
owner: string | ObjectID,
|
||||
parent: string,
|
||||
parentList: string,
|
||||
hasThumbnail: boolean,
|
||||
@@ -79,9 +80,11 @@ export interface FileInterface extends Document {
|
||||
link?: string,
|
||||
filePath?: string,
|
||||
s3ID?: string,
|
||||
personalFile? : boolean
|
||||
}
|
||||
}
|
||||
|
||||
const File = mongoose.model<FileInterface>("fs.files", fileSchema);
|
||||
|
||||
export default File;
|
||||
export default File;
|
||||
module.exports = File;
|
||||
@@ -20,8 +20,8 @@ const folderSchema = new mongoose.Schema({
|
||||
parentList: {
|
||||
type: Array,
|
||||
required:true
|
||||
}
|
||||
|
||||
},
|
||||
personalFolder: Boolean
|
||||
|
||||
}, {
|
||||
timestamps: true
|
||||
@@ -31,8 +31,11 @@ export interface FolderInterface extends Document {
|
||||
name: string,
|
||||
parent: string,
|
||||
owner: string,
|
||||
createdAt: Date,
|
||||
updatedAt: Date,
|
||||
parentList: string[],
|
||||
_doc?: any
|
||||
_doc?: any,
|
||||
personalFolder?: boolean
|
||||
}
|
||||
|
||||
const Folder = mongoose.model<FolderInterface>("Folder", folderSchema);
|
||||
|
||||
@@ -21,21 +21,26 @@ const thumbnailSchema = new mongoose.Schema({
|
||||
IV: {
|
||||
type: Buffer,
|
||||
},
|
||||
s3ID: String
|
||||
s3ID: String,
|
||||
personalFile: String,
|
||||
}, {
|
||||
timestamps: true
|
||||
})
|
||||
|
||||
export interface ThumbnailInterface extends Document {
|
||||
_id: string,
|
||||
_id: any,
|
||||
name: string,
|
||||
owner: string,
|
||||
data?: any,
|
||||
path?: string,
|
||||
IV?: Buffer,
|
||||
s3ID? : string,
|
||||
personalFile?: boolean,
|
||||
createdAt: Date,
|
||||
updatedAt: Date
|
||||
}
|
||||
|
||||
const Thumbnail = mongoose.model<ThumbnailInterface>("Thumbnail", thumbnailSchema);
|
||||
|
||||
export default Thumbnail;
|
||||
export default Thumbnail;
|
||||
module.exports = Thumbnail;
|
||||
@@ -10,7 +10,6 @@ const userSchema = new mongoose.Schema({
|
||||
name:
|
||||
{
|
||||
type:String,
|
||||
trim: true
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
@@ -38,12 +37,28 @@ const userSchema = new mongoose.Schema({
|
||||
token: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
uuid: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
time: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
}],
|
||||
tempTokens: [{
|
||||
token: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
uuid: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
time: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
}],
|
||||
privateKey: {
|
||||
@@ -51,8 +66,71 @@ const userSchema = new mongoose.Schema({
|
||||
},
|
||||
publicKey: {
|
||||
type: String,
|
||||
}
|
||||
},
|
||||
emailVerified: {
|
||||
type: Boolean
|
||||
},
|
||||
emailToken: {
|
||||
type: String,
|
||||
},
|
||||
passwordResetToken: {
|
||||
type: String
|
||||
},
|
||||
googleDriveEnabled: {
|
||||
type: Boolean
|
||||
},
|
||||
googleDriveData: {
|
||||
|
||||
id: {
|
||||
type: String
|
||||
},
|
||||
key: {
|
||||
type: String
|
||||
},
|
||||
iv: {
|
||||
type: Buffer
|
||||
},
|
||||
token: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
s3Enabled: {
|
||||
type: Boolean
|
||||
},
|
||||
s3Data: {
|
||||
id: {
|
||||
type: String
|
||||
},
|
||||
key: {
|
||||
type: String
|
||||
},
|
||||
bucket: {
|
||||
type: String
|
||||
},
|
||||
iv: {
|
||||
type: Buffer
|
||||
}
|
||||
},
|
||||
personalStorageCanceledDate: Number,
|
||||
storageData: {
|
||||
storageSize: Number,
|
||||
storageLimit: Number,
|
||||
failed: Boolean,
|
||||
},
|
||||
storageDataPersonal: {
|
||||
storageSize: Number,
|
||||
failed: Boolean,
|
||||
},
|
||||
storageDataGoogle: {
|
||||
storageSize: Number,
|
||||
storageLimit: Number,
|
||||
failed: Boolean,
|
||||
},
|
||||
activeSubscription: Boolean,
|
||||
planID: String,
|
||||
passwordLastModified: Number,
|
||||
lastSubscriptionCheckTime: Number,
|
||||
lastSubscriptionStatus: Boolean
|
||||
}, {
|
||||
timestamps: true
|
||||
})
|
||||
@@ -67,17 +145,68 @@ export interface UserInterface extends Document {
|
||||
privateKey?: string,
|
||||
publicKey?: string,
|
||||
token?: string,
|
||||
emailVerified?: boolean,
|
||||
emailToken?: string,
|
||||
passwordResetToken?: string,
|
||||
googleDriveEnabled?: boolean,
|
||||
googleDriveData?: {
|
||||
id?: string,
|
||||
key?: string,
|
||||
iv?: Buffer,
|
||||
token?: string,
|
||||
},
|
||||
s3Enabled?: boolean,
|
||||
s3Data?: {
|
||||
id?: string,
|
||||
key?: string,
|
||||
bucket?: string,
|
||||
iv?: Buffer,
|
||||
},
|
||||
storageData?: {
|
||||
storageSize?: number,
|
||||
storageLimit?: number,
|
||||
failed?: boolean,
|
||||
},
|
||||
storageDataPersonal?: {
|
||||
storageSize?: number,
|
||||
failed?: boolean,
|
||||
},
|
||||
storageDataGoogle?: {
|
||||
storageSize?: number,
|
||||
storageLimit?: number,
|
||||
failed?: boolean,
|
||||
},
|
||||
activeSubscription?: boolean,
|
||||
passwordLastModified?: number,
|
||||
personalStorageCanceledDate?: number,
|
||||
planID?: string,
|
||||
lastSubscriptionCheckTime?: number,
|
||||
lastSubscriptionStatus?: boolean,
|
||||
|
||||
getEncryptionKey: () => Buffer | undefined;
|
||||
generateTempAuthToken: () => any;
|
||||
generateTempAuthTokenVideo: (cookie: string) => any;
|
||||
generateTempAuthToken: () => Promise<any>;
|
||||
encryptToken: (tempToken: any, key: any, publicKey: any) => any;
|
||||
findByCreds: (email: string, password: string) => UserInterface;
|
||||
generateAuthToken: () => any;
|
||||
decryptToken: (encryptedToken: any, key: any, publicKey: any) => any;
|
||||
findByCreds: (email: string, password: string) => Promise<UserInterface>;
|
||||
generateAuthToken: (uuid: string | undefined) => Promise<{accessToken: string, refreshToken: string}>
|
||||
generateAuthTokenStreamVideo: (uuid: string | undefined) => Promise<string>
|
||||
generateEncryptionKeys: () => Promise<void>;
|
||||
changeEncryptionKey: (randomKey: Buffer) => void;
|
||||
changeEncryptionKey: (randomKey: Buffer) => Promise<void>;
|
||||
generateEmailVerifyToken: () => Promise<string>;
|
||||
generatePasswordResetToken: () => Promise<string>;
|
||||
encryptDriveIDandKey: (ID:string, key: string) => Promise<void>;
|
||||
decryptDriveIDandKey: () => Promise<{clientID: string, clientKey: string}>;
|
||||
encryptDriveTokenData: (token: Object) => Promise<void>;
|
||||
decryptDriveTokenData: () => Promise<any>;
|
||||
encryptS3Data: (id: string, key: string, bucket: string) => Promise<void>;
|
||||
decryptS3Data: () => Promise<{id: string, key: string, bucket: string}>
|
||||
}
|
||||
|
||||
const maxAgeAccess = 60 * 1000 * 20 + (1000 * 60);
|
||||
const maxAgeRefresh = 60 * 1000 * 60 * 24 * 30 + (1000 * 60);
|
||||
|
||||
const maxAgeAccessStreamVideo = 60 * 1000 * 60 * 24;
|
||||
|
||||
userSchema.pre("save", async function(this: any, next: any) {
|
||||
|
||||
const user = this;
|
||||
@@ -101,7 +230,6 @@ userSchema.statics.findByCreds = async(email: string, password: string) => {
|
||||
const isMatch = await bcrypt.compare(password, user.password);
|
||||
|
||||
if (!isMatch) {
|
||||
console.log("incorrect password")
|
||||
throw new Error("Incorrect password");
|
||||
}
|
||||
|
||||
@@ -117,25 +245,75 @@ userSchema.methods.toJSON = function() {
|
||||
delete userObject.password;
|
||||
delete userObject.tokens;
|
||||
delete userObject.tempTokens;
|
||||
delete userObject.privateKey;
|
||||
delete userObject.publicKey;
|
||||
|
||||
return userObject;
|
||||
}
|
||||
|
||||
userSchema.methods.generateAuthToken = async function() {
|
||||
userSchema.methods.generateAuthTokenStreamVideo = async function(uuid: string | undefined) {
|
||||
|
||||
const iv = crypto.randomBytes(16);
|
||||
|
||||
const user = this;
|
||||
let token = jwt.sign({_id:user._id.toString(), iv}, env.password!);
|
||||
const user = this;
|
||||
|
||||
const date = new Date();
|
||||
const time = date.getTime();
|
||||
|
||||
let accessTokenStreamVideo = jwt.sign({_id:user._id.toString(), iv, time}, env.passwordAccess!, {expiresIn: maxAgeAccessStreamVideo.toString()});
|
||||
|
||||
const encryptionKey = user.getEncryptionKey();
|
||||
|
||||
const encryptedToken = user.encryptToken(token, encryptionKey, iv);
|
||||
const encryptedToken = user.encryptToken(accessTokenStreamVideo, encryptionKey, iv);
|
||||
|
||||
user.tokens = user.tokens.concat({token: encryptedToken});
|
||||
uuid = uuid ? uuid : "unknown";
|
||||
|
||||
await user.save();
|
||||
return token;
|
||||
await User.updateOne({_id: user._id}, {$push: {"tempTokens": {token: encryptedToken, uuid, time}}});
|
||||
|
||||
return accessTokenStreamVideo;
|
||||
}
|
||||
|
||||
userSchema.methods.generateAuthToken = async function(uuid: string | undefined) {
|
||||
|
||||
const iv = crypto.randomBytes(16);
|
||||
|
||||
const user = this;
|
||||
|
||||
const date = new Date();
|
||||
const time = date.getTime();
|
||||
|
||||
const userObj = {_id: user._id, emailVerified: user.emailVerified || env.disableEmailVerification, email: user.email, s3Enabled: user.s3Enabled, googleDriveEnabled: user.googleDriveEnabled}
|
||||
|
||||
let accessToken = jwt.sign({user: userObj, iv}, env.passwordAccess!, {expiresIn: maxAgeAccess.toString()});
|
||||
let refreshToken = jwt.sign({_id:user._id.toString(), iv, time}, env.passwordRefresh!, {expiresIn: maxAgeRefresh.toString()});
|
||||
|
||||
const encryptionKey = user.getEncryptionKey();
|
||||
|
||||
const encryptedToken = user.encryptToken(refreshToken, encryptionKey, iv);
|
||||
|
||||
//user.tokens = user.tokens.concat({token: encryptedToken});
|
||||
|
||||
uuid = uuid ? uuid : "unknown";
|
||||
|
||||
await User.updateOne({_id: user._id}, {$push: {"tokens": {token: encryptedToken, uuid, time}}})
|
||||
|
||||
// console.log("saving user")
|
||||
// console.log("user saved")
|
||||
return {accessToken, refreshToken};
|
||||
|
||||
// const iv = crypto.randomBytes(16);
|
||||
|
||||
// const user = this;
|
||||
// let token = jwt.sign({_id:user._id.toString(), iv}, env.passwordAccess!);
|
||||
|
||||
// const encryptionKey = user.getEncryptionKey();
|
||||
|
||||
// const encryptedToken = user.encryptToken(token, encryptionKey, iv);
|
||||
|
||||
// user.tokens = user.tokens.concat({token: encryptedToken});
|
||||
|
||||
// await user.save();
|
||||
// return token;
|
||||
}
|
||||
|
||||
userSchema.methods.encryptToken = function(token: string, key: string, iv: any) {
|
||||
@@ -243,7 +421,7 @@ userSchema.methods.generateTempAuthToken = async function() {
|
||||
const iv = crypto.randomBytes(16);
|
||||
|
||||
const user = this as UserInterface;
|
||||
const token = jwt.sign({_id:user._id.toString(), iv}, env.password!, {expiresIn: "3000ms"});
|
||||
const token = jwt.sign({_id:user._id.toString(), iv}, env.passwordAccess!, {expiresIn: "3000ms"});
|
||||
|
||||
const encryptionKey = user.getEncryptionKey();
|
||||
const encryptedToken = user.encryptToken(token, encryptionKey, iv);
|
||||
@@ -254,12 +432,168 @@ userSchema.methods.generateTempAuthToken = async function() {
|
||||
return token;
|
||||
}
|
||||
|
||||
userSchema.methods.generateEmailVerifyToken = async function() {
|
||||
|
||||
const iv = crypto.randomBytes(16);
|
||||
|
||||
const user = this as UserInterface;
|
||||
const token = jwt.sign({_id:user._id.toString(), iv}, env.passwordAccess!, {expiresIn: "1d"});
|
||||
|
||||
const encryptionKey = user.getEncryptionKey();
|
||||
const encryptedToken = user.encryptToken(token, encryptionKey, iv);
|
||||
|
||||
user.emailToken = encryptedToken;
|
||||
|
||||
await user.save();
|
||||
return token;
|
||||
}
|
||||
|
||||
userSchema.methods.encryptDriveIDandKey = async function(ID: string, key: string) {
|
||||
|
||||
const iv = crypto.randomBytes(16);
|
||||
|
||||
const user = this as UserInterface;
|
||||
|
||||
const encryptedKey = user.getEncryptionKey();
|
||||
|
||||
const encryptedDriveID = user.encryptToken(ID, encryptedKey, iv);
|
||||
const encryptedDriveKey = user.encryptToken(key, encryptedKey, iv);
|
||||
|
||||
if (!user.googleDriveData) user.googleDriveData = {};
|
||||
|
||||
user.googleDriveData!.id = encryptedDriveID;
|
||||
user.googleDriveData!.key = encryptedDriveKey;
|
||||
user.googleDriveData!.iv = iv;
|
||||
|
||||
await user.save();
|
||||
}
|
||||
|
||||
userSchema.methods.decryptDriveIDandKey = async function() {
|
||||
|
||||
const user = this as UserInterface;
|
||||
|
||||
const iv = user.googleDriveData!.iv;
|
||||
|
||||
const encryptedKey = user.getEncryptionKey();
|
||||
|
||||
const encryptedDriveID = user.googleDriveData?.id;
|
||||
const encryptedDriveKey = user.googleDriveData?.key;
|
||||
|
||||
const decryptedDriveID = user.decryptToken(encryptedDriveID, encryptedKey, iv)
|
||||
const decryptedDriveKey = user.decryptToken(encryptedDriveKey, encryptedKey, iv);
|
||||
|
||||
return {
|
||||
clientID: decryptedDriveID,
|
||||
clientKey: decryptedDriveKey
|
||||
}
|
||||
}
|
||||
|
||||
userSchema.methods.encryptDriveTokenData = async function(token: Object) {
|
||||
|
||||
const user = this as UserInterface;
|
||||
const iv = user.googleDriveData?.iv;
|
||||
|
||||
const tokenToString = JSON.stringify(token);
|
||||
|
||||
const encryptedKey = user.getEncryptionKey();
|
||||
|
||||
const encryptedDriveToken = user.encryptToken(tokenToString, encryptedKey, iv);;
|
||||
|
||||
if (!user.googleDriveData) user.googleDriveData = {};
|
||||
|
||||
user.googleDriveData.token = encryptedDriveToken;
|
||||
user.googleDriveEnabled = true;
|
||||
|
||||
await user.save();
|
||||
}
|
||||
|
||||
userSchema.methods.decryptDriveTokenData = async function() {
|
||||
|
||||
const user = this as UserInterface;
|
||||
|
||||
const iv = user.googleDriveData!.iv;
|
||||
|
||||
const encryptedKey = user.getEncryptionKey();
|
||||
|
||||
const encryptedToken = user.googleDriveData?.token;
|
||||
|
||||
const decryptedToken = user.decryptToken(encryptedToken, encryptedKey, iv);
|
||||
|
||||
const tokenToObj = JSON.parse(decryptedToken);
|
||||
|
||||
return tokenToObj;
|
||||
}
|
||||
|
||||
userSchema.methods.encryptS3Data = async function(ID: string, key: string, bucket: string) {
|
||||
|
||||
const iv = crypto.randomBytes(16);
|
||||
|
||||
const user = this as UserInterface;
|
||||
|
||||
const encryptedKey = user.getEncryptionKey();
|
||||
|
||||
const encryptedS3ID = user.encryptToken(ID, encryptedKey, iv);
|
||||
const encryptedS3Key = user.encryptToken(key, encryptedKey, iv);
|
||||
const encryptedS3Bucket = user.encryptToken(bucket, encryptedKey, iv);
|
||||
|
||||
if (!user.s3Data) user.s3Data = {};
|
||||
|
||||
user.s3Data!.id = encryptedS3ID;
|
||||
user.s3Data!.key = encryptedS3Key;
|
||||
user.s3Data!.bucket = encryptedS3Bucket;
|
||||
user.s3Data!.iv = iv;
|
||||
user.s3Enabled = true;
|
||||
|
||||
await user.save();
|
||||
}
|
||||
|
||||
userSchema.methods.decryptS3Data = async function() {
|
||||
|
||||
const user = this as UserInterface;
|
||||
|
||||
const iv = user.s3Data?.iv;
|
||||
|
||||
const encryptedKey = user.getEncryptionKey();
|
||||
|
||||
const encrytpedS3ID = user.s3Data?.id;
|
||||
const encryptedS3Key = user.s3Data?.key;
|
||||
const encryptedS3Bucket = user.s3Data?.bucket;
|
||||
|
||||
const decrytpedS3ID = user.decryptToken(encrytpedS3ID, encryptedKey, iv);
|
||||
const decryptedS3Key = user.decryptToken(encryptedS3Key, encryptedKey, iv);
|
||||
const decryptedS3Bucket = user.decryptToken(encryptedS3Bucket, encryptedKey, iv);
|
||||
|
||||
//console.log("decrypted keys", decrytpedS3ID, decryptedS3Key, decryptedS3Bucket);
|
||||
|
||||
return {
|
||||
id: decrytpedS3ID,
|
||||
key: decryptedS3Key,
|
||||
bucket: decryptedS3Bucket,
|
||||
}
|
||||
}
|
||||
|
||||
userSchema.methods.generatePasswordResetToken = async function() {
|
||||
|
||||
const iv = crypto.randomBytes(16);
|
||||
|
||||
const user = this as UserInterface;
|
||||
const token = jwt.sign({_id:user._id.toString(), iv}, env.passwordAccess!, {expiresIn: "1h"});
|
||||
|
||||
const encryptionKey = user.getEncryptionKey();
|
||||
const encryptedToken = user.encryptToken(token, encryptionKey, iv);
|
||||
|
||||
user.passwordResetToken = encryptedToken;
|
||||
|
||||
await user.save();
|
||||
return token;
|
||||
}
|
||||
|
||||
userSchema.methods.generateTempAuthTokenVideo = async function(cookie: string) {
|
||||
|
||||
const iv = crypto.randomBytes(16);
|
||||
|
||||
const user = this;
|
||||
const token = jwt.sign({_id:user._id.toString(), cookie, iv}, env.password!, {expiresIn:"5h"});
|
||||
const token = jwt.sign({_id:user._id.toString(), cookie, iv}, env.passwordAccess!, {expiresIn:"5h"});
|
||||
|
||||
const encryptionKey = user.getEncryptionKey();
|
||||
const encryptedToken = user.encryptToken(token, encryptionKey, iv);
|
||||
@@ -272,4 +606,5 @@ userSchema.methods.generateTempAuthTokenVideo = async function(cookie: string) {
|
||||
|
||||
const User = mongoose.model<UserInterface>("User", userSchema);
|
||||
|
||||
export default User;
|
||||
export default User;
|
||||
module.exports = User;
|
||||
@@ -4,6 +4,11 @@ import userRouter from "../express-routers/user";
|
||||
import fileRouter from "../express-routers/file";
|
||||
import folderRouter from "../express-routers/folder";
|
||||
import storageRouter from "../express-routers/storage";
|
||||
import googleFileRouter from "../express-routers/googleFile";
|
||||
import personalFileRouter from "../express-routers/personalFile";
|
||||
import googleFolderRouter from "../express-routers/googleFolder";
|
||||
import userGoogleRouter from "../express-routers/userGoogle";
|
||||
import userPersonalRouter from "../express-routers/userPersonal";
|
||||
import bodyParser from "body-parser";
|
||||
import https from "https";
|
||||
import fs from "fs";
|
||||
@@ -11,8 +16,9 @@ import helmet from "helmet";
|
||||
import busboy from "connect-busboy";
|
||||
import compression from "compression";
|
||||
import http from "http";
|
||||
|
||||
|
||||
import cookieParser from "cookie-parser";
|
||||
import env from "../enviroment/env";
|
||||
// import requestIp from "request-ip";
|
||||
|
||||
const app = express();
|
||||
const publicPath = path.join(__dirname, "..", "..", "public");
|
||||
@@ -21,7 +27,7 @@ let server: any;
|
||||
let serverHttps: any;
|
||||
|
||||
if (process.env.SSL === 'true') {
|
||||
|
||||
|
||||
const cert = fs.readFileSync("certificate.crt")
|
||||
const ca = fs.readFileSync("certificate.ca-bundle");
|
||||
const key = fs.readFileSync("certificate.key");
|
||||
@@ -40,23 +46,26 @@ server = http.createServer(app);
|
||||
|
||||
require("../db/mongoose");
|
||||
|
||||
app.use(cookieParser(env.passwordCookie));
|
||||
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(requestIp.mw());
|
||||
|
||||
app.use(busboy({
|
||||
highWaterMark: 2 * 1024 * 1024,
|
||||
highWaterMark: 2 * 1024 * 1024,
|
||||
|
||||
}));
|
||||
|
||||
app.use(userRouter, fileRouter, folderRouter, storageRouter);
|
||||
app.use(userRouter, fileRouter, folderRouter, storageRouter, googleFileRouter, personalFileRouter, googleFolderRouter, userPersonalRouter, userGoogleRouter);
|
||||
|
||||
|
||||
const nodeMode = process.env.NODE_ENV ? "Production" : "Development/Testing";
|
||||
//const nodeMode = process.env.NODE_ENV ? "Production" : "Development/Testing";
|
||||
|
||||
console.log("Node Enviroment Mode:", nodeMode);
|
||||
//console.log("Node Enviroment Mode:", nodeMode);
|
||||
|
||||
|
||||
app.get("*", (_: Request, res: Response) => {
|
||||
@@ -64,4 +73,5 @@ app.get("*", (_: Request, res: Response) => {
|
||||
res.sendFile(path.join(publicPath, "index.html"))
|
||||
})
|
||||
|
||||
export default {server, serverHttps};
|
||||
|
||||
export default {server, serverHttps};
|
||||
|
||||
@@ -13,7 +13,7 @@ import File, { FileInterface } from "../../models/file";
|
||||
import getFileSize from "./utils/getFileSize";
|
||||
import DbUtilFile from "../../db/utils/fileUtils/index";
|
||||
import awaitStream from "./utils/awaitStream";
|
||||
import createThumbnailFS from "./utils/createThumbnailFS";
|
||||
import createThumbnailAny from "./utils/createThumbailAny";
|
||||
import imageChecker from "../../utils/imageChecker";
|
||||
import Thumbnail, {ThumbnailInterface} from "../../models/thumbnail";
|
||||
import streamToBuffer from "../../utils/streamToBuffer";
|
||||
@@ -23,7 +23,11 @@ import removeChunksFS from "./utils/removeChunksFS";
|
||||
import getPrevIVFS from "./utils/getPrevIVFS";
|
||||
import awaitStreamVideo from "./utils/awaitStreamVideo";
|
||||
import fixStartChunkLength from "./utils/fixStartChunkLength";
|
||||
import Folder from "../../models/folder";
|
||||
import Folder, { FolderInterface } from "../../models/folder";
|
||||
import addToStoageSize from "./utils/addToStorageSize";
|
||||
import subtractFromStorageSize from "./utils/subtractFromStorageSize";
|
||||
import ForbiddenError from "../../utils/ForbiddenError";
|
||||
import { ObjectID } from "mongodb";
|
||||
|
||||
const dbUtilsFile = new DbUtilFile();
|
||||
|
||||
@@ -38,8 +42,7 @@ class FileSystemService implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const initVect = crypto.randomBytes(16);
|
||||
|
||||
@@ -52,10 +55,11 @@ class FileSystemService implements ChunkInterface {
|
||||
const parent = formData.get("parent") || "/"
|
||||
const parentList = formData.get("parentList") || "/";
|
||||
const size = formData.get("size") || ""
|
||||
const personalFile = formData.get("personal-file") ? true : false;
|
||||
let hasThumbnail = false;
|
||||
let thumbnailID = ""
|
||||
const isVideo = videoChecker(filename)
|
||||
|
||||
|
||||
const systemFileName = uuid.v4();
|
||||
|
||||
const metadata = {
|
||||
@@ -88,13 +92,13 @@ class FileSystemService implements ChunkInterface {
|
||||
|
||||
await currentFile.save();
|
||||
|
||||
console.log(currentFile);
|
||||
await addToStoageSize(user, size, personalFile);
|
||||
|
||||
const imageCheck = imageChecker(currentFile.filename);
|
||||
|
||||
if (currentFile.length < 15728640 && imageCheck) {
|
||||
|
||||
const updatedFile = await createThumbnailFS(currentFile, filename, user);
|
||||
const updatedFile = await createThumbnailAny(currentFile, filename, user);
|
||||
|
||||
return updatedFile;
|
||||
|
||||
@@ -105,6 +109,47 @@ class FileSystemService implements ChunkInterface {
|
||||
|
||||
}
|
||||
|
||||
getFileWriteStream = async(user: UserInterface, file: FileInterface, parentFolder: FolderInterface) => {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const initVect = crypto.randomBytes(16);
|
||||
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
const cipher = crypto.createCipheriv('aes256', CIPHER_KEY, initVect);
|
||||
|
||||
const filename = file.filename
|
||||
const parent = parentFolder._id
|
||||
const parentList = [...parentFolder.parentList, parentFolder._id]
|
||||
const size = file.metadata.size
|
||||
const personalFile = file.metadata.personalFile ? true : false
|
||||
let hasThumbnail = file.metadata.hasThumbnail;
|
||||
let thumbnailID = file.metadata.thumbnailID
|
||||
const isVideo = file.metadata.isVideo
|
||||
|
||||
const systemFileName = uuid.v4();
|
||||
|
||||
const metadata = {
|
||||
owner: user._id,
|
||||
parent,
|
||||
parentList,
|
||||
hasThumbnail,
|
||||
thumbnailID,
|
||||
isVideo,
|
||||
size,
|
||||
IV: file.metadata.IV,
|
||||
filePath: env.fsDirectory + systemFileName
|
||||
}
|
||||
|
||||
const fileWriteStream = fs.createWriteStream(metadata.filePath);
|
||||
|
||||
return fileWriteStream;
|
||||
|
||||
}
|
||||
|
||||
downloadFile = async(user: UserInterface, fileID: string, res: Response) => {
|
||||
|
||||
const currentFile: FileInterface = await dbUtilsFile.getFileInfo(fileID, user._id);
|
||||
@@ -113,7 +158,7 @@ class FileSystemService implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const filePath = currentFile.metadata.filePath!;
|
||||
|
||||
@@ -134,17 +179,40 @@ class FileSystemService implements ChunkInterface {
|
||||
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
|
||||
}
|
||||
|
||||
getFileReadStream = async(user: UserInterface, fileID: string) => {
|
||||
|
||||
const currentFile: FileInterface = await dbUtilsFile.getFileInfo(fileID, user._id);
|
||||
|
||||
if (!currentFile) throw new NotFoundError("Download File Not Found");
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const filePath = currentFile.metadata.filePath!;
|
||||
|
||||
const IV = currentFile.metadata.IV.buffer as Buffer;
|
||||
|
||||
const readStream = fs.createReadStream(filePath);
|
||||
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV);
|
||||
|
||||
return readStream
|
||||
}
|
||||
|
||||
getThumbnail = async(user: UserInterface, id: string) => {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const thumbnail = await Thumbnail.findById(id) as ThumbnailInterface;
|
||||
const thumbnail = await Thumbnail.findById(new ObjectID(id)) as ThumbnailInterface;
|
||||
|
||||
if (thumbnail.owner !== user._id.toString()) {
|
||||
|
||||
throw new NotAuthorizedError('Thumbnail Unauthorized Error');
|
||||
throw new ForbiddenError('Thumbnail Unauthorized Error');
|
||||
}
|
||||
|
||||
const iv = thumbnail.IV!;
|
||||
@@ -174,7 +242,7 @@ class FileSystemService implements ChunkInterface {
|
||||
const password = user.getEncryptionKey();
|
||||
const IV = file.metadata.IV.buffer as Buffer;
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const readStream = fs.createReadStream(file.metadata.filePath!);
|
||||
|
||||
@@ -188,13 +256,21 @@ class FileSystemService implements ChunkInterface {
|
||||
|
||||
const allStreamsToErrorCatch = [readStream, decipher];
|
||||
|
||||
console.log("Sending Full Thumbnail...")
|
||||
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
|
||||
console.log("Full thumbnail sent");
|
||||
}
|
||||
|
||||
streamVideo = async(user: UserInterface, fileID: string, headers: any, res: Response, req: Request) => {
|
||||
|
||||
// To get this all working correctly with encryption and across
|
||||
// All browsers took many days, tears, and some of my sanity.
|
||||
// Shoutout to Tyzoid for helping me with the decryption
|
||||
// And and helping me understand how the IVs work.
|
||||
|
||||
// P.S I hate safari >:(
|
||||
// Why do yall have to be weird with video streaming
|
||||
// 90% of the issues with this are only in Safari
|
||||
// Is safari going to be the next internet explorer?
|
||||
|
||||
const userID = user._id;
|
||||
const currentFile: FileInterface = await dbUtilsFile.getFileInfo(fileID, userID);
|
||||
|
||||
@@ -202,7 +278,7 @@ class FileSystemService implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const fileSize = currentFile.metadata.size;
|
||||
|
||||
@@ -223,22 +299,56 @@ class FileSystemService implements ChunkInterface {
|
||||
|
||||
let currentIV = IV;
|
||||
|
||||
let fixedStart = start % 16 === 0 ? start : fixStartChunkLength(start);
|
||||
let fixedStart = 0;
|
||||
let fixedEnd = currentFile.length;
|
||||
|
||||
if (start === 0 && end === 1) {
|
||||
|
||||
// This is for Safari/iOS, Safari will request the first
|
||||
// Byte before actually playing the video. Needs to be
|
||||
// 16 bytes.
|
||||
|
||||
fixedStart = 0;
|
||||
fixedEnd = 15;
|
||||
|
||||
} else {
|
||||
|
||||
// If you're a normal browser, or this isn't Safari's first request
|
||||
// We need to make it so start is divisible by 16, since AES256
|
||||
// Has a block size of 16 bytes.
|
||||
|
||||
fixedStart = start % 16 === 0 ? start : fixStartChunkLength(start);
|
||||
}
|
||||
|
||||
if (+start === 0) {
|
||||
|
||||
|
||||
// This math will not work if the start is 0
|
||||
// So if it is we just change fixed start back
|
||||
// To 0.
|
||||
|
||||
fixedStart = 0;
|
||||
}
|
||||
|
||||
const fixedEnd = currentFile.length;
|
||||
|
||||
|
||||
// We also need to calculate the difference between the start and the
|
||||
// Fixed start position. Since there will be an offset if the original
|
||||
// Request is not divisible by 16, it will not return the right part
|
||||
// Of the file, you will see how we do this in the awaitStreamVideo
|
||||
// code.
|
||||
|
||||
const differenceStart = start - fixedStart;
|
||||
|
||||
|
||||
if (fixedStart !== 0 && start !== 0) {
|
||||
|
||||
// If this isn't the first request, the way AES256 works is when you try to
|
||||
// Decrypt a certain part of the file that isn't the start, the IV will
|
||||
// Actually be the 16 bytes ahead of where you are trying to
|
||||
// Start the decryption.
|
||||
|
||||
currentIV = await getPrevIVFS(fixedStart - 16, currentFile.metadata.filePath!) as Buffer;
|
||||
}
|
||||
|
||||
|
||||
const readStream = fs.createReadStream(currentFile.metadata.filePath!, {
|
||||
start: fixedStart,
|
||||
end: fixedEnd,
|
||||
@@ -256,15 +366,8 @@ class FileSystemService implements ChunkInterface {
|
||||
|
||||
readStream.pipe(decipher);
|
||||
|
||||
// req.on("close", () => {
|
||||
// // console.log("req closed");
|
||||
// readStream.destroy();
|
||||
// })
|
||||
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, allStreamsToErrorCatch, readStream);
|
||||
|
||||
const tempUUID = req.params.uuid;
|
||||
|
||||
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, tempUUID, allStreamsToErrorCatch);
|
||||
console.log("Video Stream Finished");
|
||||
readStream.destroy();
|
||||
}
|
||||
|
||||
@@ -280,7 +383,7 @@ class FileSystemService implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key");
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key");
|
||||
|
||||
const IV = file.metadata.IV.buffer as Buffer;
|
||||
|
||||
@@ -299,7 +402,6 @@ class FileSystemService implements ChunkInterface {
|
||||
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
|
||||
|
||||
if (file.metadata.linkType === "one") {
|
||||
console.log("removing public link");
|
||||
await dbUtilsFile.removeOneTimePublicLink(fileID);
|
||||
}
|
||||
}
|
||||
@@ -321,6 +423,7 @@ class FileSystemService implements ChunkInterface {
|
||||
|
||||
await removeChunksFS(file.metadata.filePath!);
|
||||
await File.deleteOne({_id: file._id});
|
||||
await subtractFromStorageSize(userID, file.length, file.metadata.personalFile!)
|
||||
}
|
||||
|
||||
deleteFolder = async(userID: string, folderID: string, parentList: string[]) => {
|
||||
@@ -362,8 +465,6 @@ class FileSystemService implements ChunkInterface {
|
||||
|
||||
deleteAll = async(userID: string) => {
|
||||
|
||||
console.log("remove all request")
|
||||
|
||||
await Folder.deleteMany({"owner": userID});
|
||||
|
||||
const fileList = await dbUtilsFile.getFileListByOwner(userID);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import mongoose from "../../db/mongoose";
|
||||
import { Response, Request } from "express";
|
||||
import DbUtilFolder from "../../db/utils/folderUtils";
|
||||
import { Response, Request } from "express";;
|
||||
import DbUtilFile from "../../db/utils/fileUtils";
|
||||
import crypto from "crypto";
|
||||
import videoChecker from "../../utils/videoChecker"
|
||||
import imageChecker from "../../utils/imageChecker"
|
||||
import { ObjectID } from "mongodb";
|
||||
import createThumbnail from "./utils/createThumbnail";
|
||||
import createThumbnailAny from "./utils/createThumbailAny";
|
||||
import Thumbnail, {ThumbnailInterface} from "../../models/thumbnail";
|
||||
import NotAuthorizedError from "../../utils/NotAuthorizedError";
|
||||
import NotFoundError from "../../utils/NotFoundError";
|
||||
@@ -14,13 +13,16 @@ import {GridFSBucketWriteStream} from "mongodb";
|
||||
import awaitStream from "./utils/awaitStream";
|
||||
import awaitUploadStream from "./utils/awaitUploadStream";
|
||||
import User, { UserInterface } from "../../models/user";
|
||||
import Folder from "../../models/folder";
|
||||
import Folder, { FolderInterface } from "../../models/folder";
|
||||
import { FileInterface } from "../../models/file";
|
||||
import getBusboyData from "./utils/getBusboyData";
|
||||
import ChunkInterface from "./utils/ChunkInterface";
|
||||
import fixStartChunkLength from "./utils/fixStartChunkLength";
|
||||
import getPrevIVMongo from "./utils/getPrevIVMongo";
|
||||
import awaitStreamVideo from "./utils/awaitStreamVideo";
|
||||
import addToStoageSize from "./utils/addToStorageSize";
|
||||
import subtractFromStorageSize from "./utils/subtractFromStorageSize";
|
||||
import ForbiddenError from "../../utils/ForbiddenError";
|
||||
|
||||
const conn = mongoose.connection;
|
||||
|
||||
@@ -36,7 +38,7 @@ class MongoService implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
let bucketStream: GridFSBucketWriteStream;
|
||||
|
||||
@@ -51,10 +53,11 @@ class MongoService implements ChunkInterface {
|
||||
const parent = formData.get("parent") || "/"
|
||||
const parentList = formData.get("parentList") || "/";
|
||||
const size = formData.get("size") || ""
|
||||
const personalFile = formData.get("personal-file") ? true : false;
|
||||
let hasThumbnail = false;
|
||||
let thumbnailID = ""
|
||||
const isVideo = videoChecker(filename)
|
||||
|
||||
|
||||
const metadata = {
|
||||
owner: user._id,
|
||||
parent,
|
||||
@@ -66,7 +69,6 @@ class MongoService implements ChunkInterface {
|
||||
IV: initVect
|
||||
}
|
||||
|
||||
|
||||
let bucket = new mongoose.mongo.GridFSBucket(conn.db);
|
||||
|
||||
bucketStream = bucket.openUploadStream(filename, {metadata});
|
||||
@@ -75,11 +77,13 @@ class MongoService implements ChunkInterface {
|
||||
|
||||
const finishedFile = await awaitUploadStream(file.pipe(cipher), bucketStream, req, allStreamsToErrorCatch) as FileInterface;
|
||||
|
||||
await addToStoageSize(user, size, personalFile);
|
||||
|
||||
const imageCheck = imageChecker(filename);
|
||||
|
||||
if (finishedFile.length < 15728640 && imageCheck) {
|
||||
|
||||
const updatedFile = await createThumbnail(finishedFile, filename, user);
|
||||
const updatedFile = await createThumbnailAny(finishedFile, filename, user);
|
||||
|
||||
return updatedFile;
|
||||
|
||||
@@ -89,6 +93,46 @@ class MongoService implements ChunkInterface {
|
||||
}
|
||||
}
|
||||
|
||||
getFileWriteStream = async(user: UserInterface, file: FileInterface, parentFolder: FolderInterface) => {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const initVect = crypto.randomBytes(16);
|
||||
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
const cipher = crypto.createCipheriv('aes256', CIPHER_KEY, initVect);
|
||||
|
||||
const filename = file.filename
|
||||
const parent = parentFolder._id
|
||||
const parentList = [...parentFolder.parentList, parentFolder._id]
|
||||
const size = file.metadata.size
|
||||
const personalFile = file.metadata.personalFile ? true : false
|
||||
let hasThumbnail = file.metadata.hasThumbnail;
|
||||
let thumbnailID = file.metadata.thumbnailID
|
||||
const isVideo = file.metadata.isVideo;
|
||||
|
||||
const metadata = {
|
||||
owner: user._id,
|
||||
parent,
|
||||
parentList,
|
||||
hasThumbnail,
|
||||
thumbnailID,
|
||||
isVideo,
|
||||
size,
|
||||
IV: file.metadata.IV
|
||||
}
|
||||
|
||||
|
||||
let bucket = new mongoose.mongo.GridFSBucket(conn.db);
|
||||
|
||||
const bucketStream = bucket.openUploadStream(filename, {metadata});
|
||||
|
||||
return bucketStream;
|
||||
}
|
||||
|
||||
downloadFile = async(user: UserInterface, fileID: string, res: Response) => {
|
||||
|
||||
const currentFile = await dbUtilsFile.getFileInfo(fileID, user._id);
|
||||
@@ -97,7 +141,7 @@ class MongoService implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const bucket = new mongoose.mongo.GridFSBucket(conn.db);
|
||||
|
||||
@@ -117,17 +161,39 @@ class MongoService implements ChunkInterface {
|
||||
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
|
||||
}
|
||||
|
||||
getFileReadStream = async(user: UserInterface, fileID: string) => {
|
||||
|
||||
const currentFile = await dbUtilsFile.getFileInfo(fileID, user._id);
|
||||
|
||||
if (!currentFile) throw new NotFoundError("Download File Not Found");
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const bucket = new mongoose.mongo.GridFSBucket(conn.db);
|
||||
|
||||
const IV = currentFile.metadata.IV.buffer as Buffer;
|
||||
const readStream = bucket.openDownloadStream(new ObjectID(fileID));
|
||||
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV);
|
||||
|
||||
return readStream
|
||||
}
|
||||
|
||||
getThumbnail = async(user: UserInterface, id: string) => {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const thumbnail = await Thumbnail.findById(id) as ThumbnailInterface;
|
||||
const thumbnail = await Thumbnail.findById(new ObjectID(id)) as ThumbnailInterface;
|
||||
|
||||
if (thumbnail.owner !== user._id.toString()) {
|
||||
|
||||
throw new NotAuthorizedError('Thumbnail Unauthorized Error');
|
||||
throw new ForbiddenError('Thumbnail Unauthorized Error');
|
||||
}
|
||||
|
||||
const iv = thumbnail.data.slice(0, 16);
|
||||
@@ -155,7 +221,7 @@ class MongoService implements ChunkInterface {
|
||||
const password = user.getEncryptionKey();
|
||||
const IV = file.metadata.IV.buffer as Buffer;
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const readStream = bucket.openDownloadStream(new ObjectID(fileID))
|
||||
|
||||
@@ -167,12 +233,9 @@ class MongoService implements ChunkInterface {
|
||||
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
|
||||
res.set('Content-Length', file.metadata.size.toString());
|
||||
|
||||
console.log("Sending Full Thumbnail...")
|
||||
|
||||
const allStreamsToErrorCatch = [readStream, decipher];
|
||||
|
||||
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
|
||||
console.log("Full thumbnail sent");
|
||||
}
|
||||
|
||||
getPublicDownload = async(fileID: string, tempToken: any, res: Response) => {
|
||||
@@ -187,7 +250,7 @@ class MongoService implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key");
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key");
|
||||
|
||||
const bucket = new mongoose.mongo.GridFSBucket(conn.db);
|
||||
|
||||
@@ -208,13 +271,26 @@ class MongoService implements ChunkInterface {
|
||||
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
|
||||
|
||||
if (file.metadata.linkType === "one") {
|
||||
console.log("removing public link");
|
||||
await dbUtilsFile.removeOneTimePublicLink(fileID);
|
||||
}
|
||||
}
|
||||
|
||||
streamVideo = async(user: UserInterface, fileID: string, headers: any, res: Response, req: Request) => {
|
||||
|
||||
// THIS ISN'T WORKING FULLY WHEN USING MONGODB AND SAFARI,
|
||||
// OTHER DATABASES SHOULD WORK, BUT I AM NOT SURE WHY
|
||||
// IT WILL NOT WORK ON SAFARI SOMETIMES
|
||||
|
||||
// To get this all working correctly with encryption and across
|
||||
// All browsers took many days, tears, and some of my sanity.
|
||||
// Shoutout to Tyzoid for helping me with the decryption
|
||||
// And and helping me understand how the IVs work.
|
||||
|
||||
// P.S I hate safari >:(
|
||||
// Why do yall have to be weird with video streaming
|
||||
// 90% of the issues with this are only in Safari
|
||||
// Is safari going to be the next internet explorer?
|
||||
|
||||
const userID = user._id;
|
||||
const currentFile = await dbUtilsFile.getFileInfo(fileID, userID);
|
||||
|
||||
@@ -222,7 +298,7 @@ class MongoService implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const fileSize = currentFile.metadata.size;
|
||||
|
||||
@@ -243,24 +319,60 @@ class MongoService implements ChunkInterface {
|
||||
|
||||
let currentIV = IV;
|
||||
|
||||
let fixedStart = start % 16 === 0 ? start : fixStartChunkLength(start);
|
||||
let fixedStart = 0;
|
||||
let fixedEnd = currentFile.length;
|
||||
|
||||
if (start === 0 && end === 1) {
|
||||
|
||||
// This is for Safari/iOS, Safari will request the first
|
||||
// Byte before actually playing the video. Needs to be
|
||||
// 16 bytes.
|
||||
|
||||
fixedStart = 0;
|
||||
fixedEnd = 16;
|
||||
|
||||
// I am not sure why this needs to be 16 for mongoDB, on the other routes 15 works
|
||||
// Fine, and I thought the start and end were inclusive, but I am really not sure
|
||||
// At this point
|
||||
|
||||
} else {
|
||||
|
||||
// If you're a normal browser, or this isn't Safari's first request
|
||||
// We need to make it so start is divisible by 16, since AES256
|
||||
// Has a block size of 16 bytes.
|
||||
|
||||
fixedStart = start % 16 === 0 ? start : fixStartChunkLength(start);
|
||||
}
|
||||
|
||||
if (+start === 0) {
|
||||
|
||||
// This math will not work if the start is 0
|
||||
// So if it is we just change fixed start back
|
||||
// To 0.
|
||||
|
||||
fixedStart = 0;
|
||||
}
|
||||
|
||||
const fixedEnd = currentFile.length;
|
||||
// We also need to calculate the difference between the start and the
|
||||
// Fixed start position. Since there will be an offset if the original
|
||||
// Request is not divisible by 16, it will not return the right part
|
||||
// Of the file, you will see how we do this in the awaitStreamVideo
|
||||
// code.
|
||||
|
||||
const differenceStart = start - fixedStart;
|
||||
|
||||
|
||||
if (fixedStart !== 0 && start !== 0) {
|
||||
|
||||
// If this isn't the first request, the way AES256 works is when you try to
|
||||
// Decrypt a certain part of the file that isn't the start, the IV will
|
||||
// Actually be the 16 bytes ahead of where you are trying to
|
||||
// Start the decryption.
|
||||
|
||||
currentIV = await getPrevIVMongo(fixedStart - 16, fileID) as Buffer;
|
||||
}
|
||||
|
||||
const bucket = new mongoose.mongo.GridFSBucket(conn.db, {
|
||||
chunkSizeBytes: 1024
|
||||
});
|
||||
|
||||
const readStream = bucket.openDownloadStream(new ObjectID(fileID), {
|
||||
@@ -268,26 +380,19 @@ class MongoService implements ChunkInterface {
|
||||
end: fixedEnd,
|
||||
});
|
||||
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
res.writeHead(206, head);
|
||||
|
||||
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, currentIV);
|
||||
decipher.setAutoPadding(false);
|
||||
|
||||
res.writeHead(206, head);
|
||||
|
||||
const allStreamsToErrorCatch = [readStream, decipher];
|
||||
|
||||
readStream.pipe(decipher);
|
||||
|
||||
// req.on("close", () => {
|
||||
// // console.log("req closed");
|
||||
// readStream.destroy();
|
||||
// })
|
||||
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, allStreamsToErrorCatch, readStream);
|
||||
|
||||
|
||||
const tempUUID = req.params.uuid;
|
||||
|
||||
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, tempUUID, allStreamsToErrorCatch);
|
||||
readStream.destroy();
|
||||
}
|
||||
|
||||
@@ -307,6 +412,7 @@ class MongoService implements ChunkInterface {
|
||||
}
|
||||
|
||||
await bucket.delete(new ObjectID(fileID));
|
||||
await subtractFromStorageSize(userID, file.length, file.metadata.personalFile!);
|
||||
}
|
||||
|
||||
deleteFolder = async(userID: string, folderID: string, parentList: string[]) => {
|
||||
@@ -347,8 +453,6 @@ class MongoService implements ChunkInterface {
|
||||
|
||||
deleteAll = async(userID: string) => {
|
||||
|
||||
console.log("remove all request")
|
||||
|
||||
let bucket = new mongoose.mongo.GridFSBucket(conn.db, {
|
||||
chunkSizeBytes: 1024 * 255
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ import videoChecker from "../../utils/videoChecker";
|
||||
import uuid from "uuid";
|
||||
import awaitUploadStreamS3 from "./utils/awaitUploadStreamS3";
|
||||
import awaitStream from "./utils/awaitStream";
|
||||
import createThumbnailS3 from "./utils/createThumbnailS3";
|
||||
import createThumbnailAny from "./utils/createThumbailAny";
|
||||
import imageChecker from "../../utils/imageChecker";
|
||||
import Thumbnail, {ThumbnailInterface} from "../../models/thumbnail";
|
||||
import streamToBuffer from "../../utils/streamToBuffer";
|
||||
@@ -21,9 +21,14 @@ import fixStartChunkLength from "./utils/fixStartChunkLength";
|
||||
import fixEndChunkLength from "./utils/fixEndChunkLength";
|
||||
import getPrevIVS3 from "./utils/getPrevIVS3";
|
||||
import awaitStreamVideo from "./utils/awaitStreamVideo";
|
||||
import Folder from "../../models/folder";
|
||||
|
||||
import Folder, { FolderInterface } from "../../models/folder";
|
||||
import DbUtilFile from "../../db/utils/fileUtils/index";
|
||||
import s3Auth from "../../db/S3Personal";
|
||||
import addToStoageSize from "./utils/addToStorageSize";
|
||||
import subtractFromStorageSize from "./utils/subtractFromStorageSize";
|
||||
import ForbiddenError from "../../utils/ForbiddenError";
|
||||
import { ObjectID } from "mongodb";
|
||||
|
||||
const dbUtilsFile = new DbUtilFile();
|
||||
|
||||
class S3Service implements ChunkInterface {
|
||||
@@ -36,7 +41,7 @@ class S3Service implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const initVect = crypto.randomBytes(16);
|
||||
|
||||
@@ -49,13 +54,17 @@ class S3Service implements ChunkInterface {
|
||||
const parent = formData.get("parent") || "/"
|
||||
const parentList = formData.get("parentList") || "/";
|
||||
const size = formData.get("size") || ""
|
||||
const personalFile = formData.get("personal-file") ? true : false;
|
||||
let hasThumbnail = false;
|
||||
let thumbnailID = ""
|
||||
const isVideo = videoChecker(filename)
|
||||
|
||||
const randomS3ID = uuid.v4();
|
||||
|
||||
const metadata = {
|
||||
|
||||
const s3Data: any = personalFile ? await user.decryptS3Data() : {};
|
||||
const bucketName = personalFile ? s3Data.bucket : env.s3Bucket;
|
||||
|
||||
let metadata: any = {
|
||||
owner: user._id,
|
||||
parent,
|
||||
parentList,
|
||||
@@ -64,16 +73,18 @@ class S3Service implements ChunkInterface {
|
||||
isVideo,
|
||||
size,
|
||||
IV: initVect,
|
||||
s3ID: randomS3ID
|
||||
s3ID: randomS3ID,
|
||||
}
|
||||
|
||||
if (personalFile) metadata = {...metadata, personalFile: true}
|
||||
|
||||
const params = {
|
||||
Bucket: env.s3Bucket,
|
||||
Bucket: bucketName,
|
||||
Body : file.pipe(cipher),
|
||||
Key : randomS3ID
|
||||
};
|
||||
|
||||
await awaitUploadStreamS3(params);
|
||||
await awaitUploadStreamS3(params, personalFile, s3Data);
|
||||
|
||||
const date = new Date();
|
||||
const encryptedFileSize = size;
|
||||
@@ -87,12 +98,13 @@ class S3Service implements ChunkInterface {
|
||||
|
||||
await currentFile.save();
|
||||
|
||||
await addToStoageSize(user, size, personalFile);
|
||||
|
||||
const imageCheck = imageChecker(currentFile.filename);
|
||||
|
||||
if (currentFile.length < 15728640 && imageCheck) {
|
||||
|
||||
console.log("Creating thumbnail...")
|
||||
const updatedFile = await createThumbnailS3(currentFile, filename, user);
|
||||
const updatedFile = await createThumbnailAny(currentFile, filename, user);
|
||||
|
||||
return updatedFile;
|
||||
|
||||
@@ -102,6 +114,77 @@ class S3Service implements ChunkInterface {
|
||||
}
|
||||
}
|
||||
|
||||
getFileWriteStream = async(user: UserInterface, file: FileInterface, parentFolder: FolderInterface, readStream: any) => {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const initVect = crypto.randomBytes(16);
|
||||
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
const cipher = crypto.createCipheriv('aes256', CIPHER_KEY, initVect);
|
||||
|
||||
const filename = file.filename
|
||||
const parent = parentFolder._id
|
||||
const parentList = [...parentFolder.parentList, parentFolder._id]
|
||||
const size = file.metadata.size
|
||||
const personalFile = file.metadata.personalFile ? true : false
|
||||
let hasThumbnail = file.metadata.hasThumbnail;
|
||||
let thumbnailID = file.metadata.thumbnailID
|
||||
const isVideo = file.metadata.isVideo
|
||||
|
||||
const metadata = {
|
||||
owner: user._id,
|
||||
parent,
|
||||
parentList,
|
||||
hasThumbnail,
|
||||
thumbnailID,
|
||||
isVideo,
|
||||
size,
|
||||
IV: file.metadata.IV,
|
||||
s3ID: file.metadata.s3ID,
|
||||
personalFile
|
||||
}
|
||||
|
||||
const s3Data: any = personalFile ? await user.decryptS3Data() : {};
|
||||
const bucketName = personalFile ? s3Data.bucket : env.s3Bucket;
|
||||
|
||||
const params = {
|
||||
Bucket: bucketName,
|
||||
Body : readStream,
|
||||
Key : file.metadata.s3ID
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
getS3AuthThumbnail = async (thumbnail: ThumbnailInterface, user: UserInterface) => {
|
||||
|
||||
if (thumbnail.personalFile) {
|
||||
|
||||
const s3Data = await user.decryptS3Data();
|
||||
//console.log("s3 data", s3Data)
|
||||
return {s3Storage: s3Auth(s3Data.id, s3Data.key), bucket: s3Data.bucket};
|
||||
} else {
|
||||
|
||||
return {s3Storage: s3, bucket: env.s3Bucket};
|
||||
}
|
||||
}
|
||||
|
||||
getS3Auth = async (file: FileInterface, user: UserInterface) => {
|
||||
|
||||
if (file.metadata.personalFile) {
|
||||
|
||||
const s3Data = await user.decryptS3Data();
|
||||
//console.log("s3 data", s3Data)
|
||||
return {s3Storage: s3Auth(s3Data.id, s3Data.key), bucket: s3Data.bucket};
|
||||
} else {
|
||||
|
||||
return {s3Storage: s3, bucket: env.s3Bucket};
|
||||
}
|
||||
}
|
||||
|
||||
downloadFile = async(user: UserInterface, fileID: string, res: Response) => {
|
||||
|
||||
const currentFile: FileInterface = await dbUtilsFile.getFileInfo(fileID, user._id);
|
||||
@@ -110,7 +193,9 @@ class S3Service implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key");
|
||||
|
||||
const {s3Storage, bucket} = await this.getS3Auth(currentFile, user);
|
||||
|
||||
const IV = currentFile.metadata.IV.buffer as Buffer;
|
||||
|
||||
@@ -122,18 +207,52 @@ class S3Service implements ChunkInterface {
|
||||
res.set('Content-Disposition', 'attachment; filename="' + currentFile.filename + '"');
|
||||
res.set('Content-Length', currentFile.metadata.size.toString());
|
||||
|
||||
const params: any = {Bucket: env.s3Bucket, Key: currentFile.metadata.s3ID!};
|
||||
const params: any = {Bucket: bucket, Key: currentFile.metadata.s3ID!};
|
||||
|
||||
const s3ReadStream = s3.getObject(params).createReadStream();
|
||||
const s3ReadStream = s3Storage.getObject(params).createReadStream();
|
||||
|
||||
const allStreamsToErrorCatch = [s3ReadStream, decipher];
|
||||
|
||||
await awaitStream(s3ReadStream.pipe(decipher), res, allStreamsToErrorCatch);
|
||||
}
|
||||
|
||||
getFileReadStream = async(user: UserInterface, fileID: string) => {
|
||||
|
||||
const currentFile: FileInterface = await dbUtilsFile.getFileInfo(fileID, user._id);
|
||||
|
||||
if (!currentFile) throw new NotFoundError("Download File Not Found");
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key");
|
||||
|
||||
const {s3Storage, bucket} = await this.getS3Auth(currentFile, user);
|
||||
|
||||
const IV = currentFile.metadata.IV.buffer as Buffer;
|
||||
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV);
|
||||
|
||||
const params: any = {Bucket: bucket, Key: currentFile.metadata.s3ID!};
|
||||
|
||||
const s3ReadStream = s3Storage.getObject(params).createReadStream();
|
||||
|
||||
return s3ReadStream
|
||||
}
|
||||
|
||||
streamVideo = async(user: UserInterface, fileID: string, headers: any, res: Response, req: Request) => {
|
||||
|
||||
// To get this all working correctly with encryption and across
|
||||
// All browsers took many days, tears, and some of my sanity.
|
||||
// Shoutout to Tyzoid for helping me with the decryption
|
||||
// And and helping me understand how the IVs work.
|
||||
|
||||
// P.S I hate safari >:(
|
||||
// Why do yall have to be weird with video streaming
|
||||
// 90% of the issues with this are only in Safari
|
||||
// Is safari going to be the next internet explorer?
|
||||
|
||||
const userID = user._id;
|
||||
const currentFile: FileInterface = await dbUtilsFile.getFileInfo(fileID, userID);
|
||||
|
||||
@@ -141,9 +260,11 @@ class S3Service implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const fileSize = currentFile.metadata.size;
|
||||
|
||||
const isPersonal = currentFile.metadata.personalFile!;
|
||||
|
||||
const range = headers.range
|
||||
const parts = range.replace(/bytes=/, "").split("-")
|
||||
@@ -162,76 +283,85 @@ class S3Service implements ChunkInterface {
|
||||
|
||||
let currentIV = IV;
|
||||
|
||||
let fixedStart = start % 16 === 0 ? start : fixStartChunkLength(start);
|
||||
|
||||
let fixedStart = 0;
|
||||
let fixedEnd = currentFile.length;
|
||||
|
||||
if (start === 0 && end === 1) {
|
||||
|
||||
// This is for Safari/iOS, Safari will request the first
|
||||
// Byte before actually playing the video. Needs to be
|
||||
// 16 bytes.
|
||||
|
||||
fixedStart = 0;
|
||||
fixedEnd = 15;
|
||||
|
||||
} else {
|
||||
|
||||
// If you're a normal browser, or this isn't Safari's first request
|
||||
// We need to make it so start is divisible by 16, since AES256
|
||||
// Has a block size of 16 bytes.
|
||||
|
||||
fixedStart = start % 16 === 0 ? start : fixStartChunkLength(start);
|
||||
|
||||
// I goofed up and forgot to add the encrypted file size to S3 data,
|
||||
// It just used the normal file size :(
|
||||
// So you'll notice only on the S3 route do i need to fix the end length
|
||||
// To, this is because the other 2 routes use the encrypted file size
|
||||
// Which is always a multiple of 16. I cannot change this now
|
||||
// Since previous versions will still have the issue, but
|
||||
// This is a simple fix luckily.
|
||||
|
||||
fixedEnd = fixedEnd % 16 === 0 ? fixedEnd : fixEndChunkLength(fixedEnd)
|
||||
}
|
||||
|
||||
if (+start === 0) {
|
||||
|
||||
|
||||
// This math will not work if the start is 0
|
||||
// So if it is we just change fixed start back
|
||||
// To 0.
|
||||
|
||||
fixedStart = 0;
|
||||
}
|
||||
|
||||
const fixedEnd = fileSize % 16 === 0 ? fileSize : fixEndChunkLength(fileSize); //end % 16 === 0 ? end + 15: (fixEndChunkLength(end) - 1) + 16;
|
||||
|
||||
// We also need to calculate the difference between the start and the
|
||||
// Fixed start position. Since there will be an offset if the original
|
||||
// Request is not divisible by 16, it will not return the right part
|
||||
// Of the file, you will see how we do this in the awaitStreamVideo
|
||||
// code.
|
||||
|
||||
const differenceStart = start - fixedStart;
|
||||
|
||||
|
||||
if (fixedStart !== 0 && start !== 0) {
|
||||
|
||||
// If this isn't the first request, the way AES256 works is when you try to
|
||||
// Decrypt a certain part of the file that isn't the start, the IV will
|
||||
// Actually be the 16 bytes ahead of where you are trying to
|
||||
// Start the decryption.
|
||||
|
||||
currentIV = await getPrevIVS3(fixedStart - 16, currentFile.metadata.s3ID!) as Buffer;
|
||||
currentIV = await getPrevIVS3(fixedStart - 16, currentFile.metadata.s3ID!, isPersonal, user) as Buffer;
|
||||
}
|
||||
|
||||
const params: any = {Bucket: env.s3Bucket, Key: currentFile.metadata.s3ID!, Range: `bytes=${fixedStart}-${fixedEnd}`};
|
||||
const {s3Storage, bucket} = await this.getS3Auth(currentFile, user);
|
||||
|
||||
const s3ReadStream = s3.getObject(params).createReadStream();
|
||||
const params: any = {Bucket: bucket, Key: currentFile.metadata.s3ID!, Range: `bytes=${fixedStart}-${fixedEnd}`};
|
||||
|
||||
const s3ReadStream = s3Storage.getObject(params).createReadStream();
|
||||
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, currentIV);
|
||||
|
||||
decipher.setAutoPadding(false);
|
||||
|
||||
res.writeHead(206, head);
|
||||
|
||||
const allStreamsToErrorCatch = [s3ReadStream, decipher];
|
||||
|
||||
s3ReadStream.pipe(decipher);
|
||||
|
||||
const tempUUID = req.params.uuid;
|
||||
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, allStreamsToErrorCatch, s3ReadStream);
|
||||
|
||||
// s3ReadStream.on("data", () => {
|
||||
// console.log("data", tempUUID);
|
||||
// })
|
||||
|
||||
|
||||
// req.on("close", () => {
|
||||
// // console.log("Destoying read stream");
|
||||
// // s3ReadStream.destroy();
|
||||
// // console.log("Read Stream Destroyed");
|
||||
// })
|
||||
|
||||
// req.on("end", () => {
|
||||
// console.log("ending stream");
|
||||
// s3ReadStream.destroy();
|
||||
// console.log("ended stream")
|
||||
// })
|
||||
|
||||
// req.on("error", () => {
|
||||
// console.log("req error");
|
||||
// })
|
||||
|
||||
// req.on("pause", () => {
|
||||
// console.log("req pause")
|
||||
// })
|
||||
|
||||
// req.on("close", () => {
|
||||
// // console.log("req closed");
|
||||
// s3ReadStream.destroy();
|
||||
// })
|
||||
|
||||
//req.on("")
|
||||
|
||||
// req.on("end", () => {
|
||||
// console.log("req end");
|
||||
// })
|
||||
|
||||
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, tempUUID, allStreamsToErrorCatch);
|
||||
console.log("Video stream finished");
|
||||
s3ReadStream.destroy();
|
||||
}
|
||||
|
||||
@@ -239,24 +369,26 @@ class S3Service implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const thumbnail = await Thumbnail.findById(id) as ThumbnailInterface;
|
||||
const thumbnail = await Thumbnail.findById(new ObjectID(id)) as ThumbnailInterface;
|
||||
|
||||
if (thumbnail.owner !== user._id.toString()) {
|
||||
|
||||
throw new NotAuthorizedError('Thumbnail Unauthorized Error');
|
||||
throw new ForbiddenError('Thumbnail Unauthorized Error');
|
||||
}
|
||||
|
||||
const iv = thumbnail.IV!;
|
||||
|
||||
const {s3Storage, bucket} = await this.getS3AuthThumbnail(thumbnail, user);
|
||||
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
const decipher = crypto.createDecipheriv("aes256", CIPHER_KEY, iv);
|
||||
|
||||
const params: any = {Bucket: env.s3Bucket, Key: thumbnail.s3ID!};
|
||||
const params: any = {Bucket: bucket, Key: thumbnail.s3ID!};
|
||||
|
||||
const readStream = s3.getObject(params).createReadStream();
|
||||
const readStream = s3Storage.getObject(params).createReadStream();
|
||||
|
||||
const allStreamsToErrorCatch = [readStream, decipher];
|
||||
|
||||
@@ -276,11 +408,13 @@ class S3Service implements ChunkInterface {
|
||||
const password = user.getEncryptionKey();
|
||||
const IV = file.metadata.IV.buffer as Buffer;
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key")
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key")
|
||||
|
||||
const params: any = {Bucket: env.s3Bucket, Key: file.metadata.s3ID!};
|
||||
const {s3Storage, bucket} = await this.getS3Auth(file, user);
|
||||
|
||||
const readStream = s3.getObject(params).createReadStream();
|
||||
const params: any = {Bucket: bucket, Key: file.metadata.s3ID!};
|
||||
|
||||
const readStream = s3Storage.getObject(params).createReadStream();
|
||||
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
@@ -292,9 +426,7 @@ class S3Service implements ChunkInterface {
|
||||
|
||||
const allStreamsToErrorCatch = [readStream, decipher];
|
||||
|
||||
console.log("Sending Full Thumbnail...")
|
||||
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
|
||||
console.log("Full thumbnail sent");
|
||||
}
|
||||
|
||||
getPublicDownload = async(fileID: string, tempToken: any, res: Response) => {
|
||||
@@ -309,13 +441,15 @@ class S3Service implements ChunkInterface {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
if (!password) throw new NotAuthorizedError("Invalid Encryption Key");
|
||||
if (!password) throw new ForbiddenError("Invalid Encryption Key");
|
||||
|
||||
const IV = file.metadata.IV.buffer as Buffer;
|
||||
|
||||
const params: any = {Bucket: env.s3Bucket, Key: file.metadata.s3ID!};
|
||||
|
||||
const readStream = s3.getObject(params).createReadStream();
|
||||
const {s3Storage, bucket} = await this.getS3Auth(file, user);
|
||||
|
||||
const params: any = {Bucket: bucket, Key: file.metadata.s3ID!};
|
||||
|
||||
const readStream = s3Storage.getObject(params).createReadStream();
|
||||
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
@@ -330,7 +464,6 @@ class S3Service implements ChunkInterface {
|
||||
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
|
||||
|
||||
if (file.metadata.linkType === "one") {
|
||||
console.log("removing public link");
|
||||
await dbUtilsFile.removeOneTimePublicLink(fileID);
|
||||
}
|
||||
}
|
||||
@@ -340,18 +473,23 @@ class S3Service implements ChunkInterface {
|
||||
const file: FileInterface = await dbUtilsFile.getFileInfo(fileID, userID);
|
||||
|
||||
if (!file) throw new NotFoundError("Delete File Not Found Error");
|
||||
|
||||
const user = await User.findById(userID) as UserInterface;
|
||||
|
||||
const {s3Storage, bucket} = await this.getS3Auth(file, user);
|
||||
|
||||
if (file.metadata.thumbnailID) {
|
||||
|
||||
const thumbnail = await Thumbnail.findById(file.metadata.thumbnailID) as ThumbnailInterface;
|
||||
const paramsThumbnail: any = {Bucket: env.s3Bucket, Key: thumbnail.s3ID!};
|
||||
await removeChunksS3(paramsThumbnail);
|
||||
const paramsThumbnail: any = {Bucket: bucket, Key: thumbnail.s3ID!};
|
||||
await removeChunksS3(s3Storage, paramsThumbnail);
|
||||
await Thumbnail.deleteOne({_id: file.metadata.thumbnailID});
|
||||
}
|
||||
|
||||
const params: any = {Bucket: env.s3Bucket, Key: file.metadata.s3ID!};
|
||||
await removeChunksS3(params);
|
||||
const params: any = {Bucket: bucket, Key: file.metadata.s3ID!};
|
||||
await removeChunksS3(s3Storage, params);
|
||||
await File.deleteOne({_id: file._id});
|
||||
await subtractFromStorageSize(userID, file.length, file.metadata.personalFile!);
|
||||
}
|
||||
|
||||
deleteFolder = async(userID: string, folderID: string, parentList: string[]) => {
|
||||
@@ -364,23 +502,27 @@ class S3Service implements ChunkInterface {
|
||||
const fileList = await dbUtilsFile.getFileListByParent(userID, parentListString);
|
||||
|
||||
if (!fileList) throw new NotFoundError("Delete File List Not Found");
|
||||
|
||||
|
||||
const user = await User.findById(userID) as UserInterface;
|
||||
|
||||
for (let i = 0; i < fileList.length; i++) {
|
||||
|
||||
const currentFile = fileList[i];
|
||||
|
||||
const {s3Storage, bucket} = await this.getS3Auth(currentFile, user);
|
||||
|
||||
try {
|
||||
|
||||
if (currentFile.metadata.thumbnailID) {
|
||||
|
||||
const thumbnail = await Thumbnail.findById(currentFile.metadata.thumbnailID) as ThumbnailInterface;
|
||||
const paramsThumbnail: any = {Bucket: env.s3Bucket, Key: thumbnail.s3ID!};
|
||||
await removeChunksS3(paramsThumbnail);
|
||||
const paramsThumbnail: any = {Bucket: bucket, Key: thumbnail.s3ID!};
|
||||
await removeChunksS3(s3Storage, paramsThumbnail);
|
||||
await Thumbnail.deleteOne({_id: currentFile.metadata.thumbnailID});
|
||||
}
|
||||
|
||||
const params: any = {Bucket: env.s3Bucket, Key: currentFile.metadata.s3ID!};
|
||||
await removeChunksS3(params);
|
||||
const params: any = {Bucket: bucket, Key: currentFile.metadata.s3ID!};
|
||||
await removeChunksS3(s3Storage, params);
|
||||
await File.deleteOne({_id: currentFile._id});
|
||||
|
||||
} catch (e) {
|
||||
@@ -393,29 +535,31 @@ class S3Service implements ChunkInterface {
|
||||
|
||||
deleteAll = async(userID: string) => {
|
||||
|
||||
console.log("remove all request")
|
||||
|
||||
await Folder.deleteMany({"owner": userID});
|
||||
|
||||
const fileList = await dbUtilsFile.getFileListByOwner(userID);
|
||||
|
||||
if (!fileList) throw new NotFoundError("Delete All File List Not Found Error");
|
||||
|
||||
const user = await User.findById(userID) as UserInterface;
|
||||
|
||||
for (let i = 0; i < fileList.length; i++) {
|
||||
const currentFile = fileList[i];
|
||||
|
||||
const {s3Storage, bucket} = await this.getS3Auth(currentFile, user);
|
||||
|
||||
try {
|
||||
|
||||
if (currentFile.metadata.thumbnailID) {
|
||||
|
||||
const thumbnail = await Thumbnail.findById(currentFile.metadata.thumbnailID) as ThumbnailInterface;
|
||||
const paramsThumbnail: any = {Bucket: env.s3Bucket, Key: thumbnail.s3ID!};
|
||||
await removeChunksS3(paramsThumbnail);
|
||||
const paramsThumbnail: any = {Bucket: bucket, Key: thumbnail.s3ID!};
|
||||
await removeChunksS3(s3Storage, paramsThumbnail);
|
||||
await Thumbnail.deleteOne({_id: currentFile.metadata.thumbnailID});
|
||||
}
|
||||
|
||||
const params: any = {Bucket: env.s3Bucket, Key: currentFile.metadata.s3ID!};
|
||||
await removeChunksS3(params);
|
||||
const params: any = {Bucket: bucket, Key: currentFile.metadata.s3ID!};
|
||||
await removeChunksS3(s3Storage, params);
|
||||
await File.deleteOne({_id: currentFile._id});
|
||||
|
||||
} catch (e) {
|
||||
|
||||
@@ -9,6 +9,7 @@ interface ChunkInterface {
|
||||
getFullThumbnail: (user: UserInterface, fileID: string, res: Response) => void;
|
||||
getPublicDownload: (fileID: string, tempToken: any, res: Response) => void;
|
||||
streamVideo: (user: UserInterface, fileID: string, headers: any, res: Response, req: Request) => void;
|
||||
getFileReadStream: (user: UserInterface, fileID: string) => any
|
||||
}
|
||||
|
||||
export default ChunkInterface;
|
||||
@@ -0,0 +1,20 @@
|
||||
import {UserInterface} from "../../../models/user";
|
||||
import env from "../../../enviroment/env";
|
||||
|
||||
const addToStoageSize = async(user: UserInterface, size: number, isPersonalFile: boolean) => {
|
||||
|
||||
if (isPersonalFile) {
|
||||
//console.log("user storage")
|
||||
user.storageDataPersonal!.storageSize = +user.storageDataPersonal!.storageSize! + +size;
|
||||
await user.save()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user.storageData || (!user.storageData.storageSize && !user.storageData.storageLimit)) user.storageData = {storageSize: 0, storageLimit: 0};
|
||||
|
||||
user.storageData!.storageSize = +user.storageData!.storageSize! + +size;
|
||||
|
||||
await user.save();
|
||||
}
|
||||
|
||||
export default addToStoageSize;
|
||||
@@ -15,7 +15,6 @@ const awaitStream = <T>(inputSteam: any, outputStream: any, allStreamsToErrorCat
|
||||
})
|
||||
|
||||
inputSteam.pipe(outputStream).on("finish", (data: T) => {
|
||||
console.log("await stream finished")
|
||||
resolve(data);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,107 +1,21 @@
|
||||
import {Response, Request} from "express"
|
||||
import tempStorage from "../../../tempStorage/tempStorage";
|
||||
import uuid from "uuid";
|
||||
const StreamSkip = require("stream-skip");
|
||||
|
||||
const awaitStreamVideo = (start: number, end:number, differenceStart: number,
|
||||
decipher: any, res: Response, req: Request, tempUUID: string, streamsToErrorCatch: any[]) => {
|
||||
|
||||
const currentUUID = uuid.v4();
|
||||
tempStorage[tempUUID] = currentUUID;
|
||||
decipher: any, res: Response, req: Request, streamsToErrorCatch: any[], readStream: any) => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let firstBytesRemoved = false;
|
||||
//let sizeCounter = 0;
|
||||
|
||||
req.on("close", () => {
|
||||
//console.log("close resolved");
|
||||
streamsToErrorCatch.forEach((stream) => {
|
||||
stream.destroy();
|
||||
})
|
||||
// readStream.close();
|
||||
decipher.destroy();
|
||||
resolve();
|
||||
})
|
||||
|
||||
req.on("end", () => {
|
||||
//console.log("End resolved");
|
||||
resolve();
|
||||
})
|
||||
|
||||
decipher.on("data", (data: Buffer | string) => {
|
||||
|
||||
//console.log("check", tempStorage[tempUUID]);
|
||||
//console.log("check b", tempStorage[tempUUID] !== currentUUID && tempStorage[tempUUID] !== undefined);
|
||||
|
||||
//console.log(tempStorage[tempUUID] !== currentUUID, tempStorage[tempUUID])
|
||||
if (tempStorage[tempUUID] !== currentUUID) {
|
||||
|
||||
//console.log("New Stream Requested, Desroying old stream");
|
||||
|
||||
streamsToErrorCatch.forEach((stream) => {
|
||||
stream.destroy();
|
||||
})
|
||||
|
||||
//console.log("Old Stream Desroyed");
|
||||
//console.log("Old Stream Resolved");
|
||||
resolve();
|
||||
//delete tempStorage[tempUUID];
|
||||
}
|
||||
|
||||
//console.log("data", currentUUID);
|
||||
|
||||
//console.log("stream passed", currentUUID);
|
||||
|
||||
// if (tempStorage[tempUUID] !== undefined && tempStorage[tempUUID] !== currentUUID) {
|
||||
|
||||
// console.log("New Stream Requested, Desroying old stream");
|
||||
// streamsToErrorCatch[0].destroy();
|
||||
// console.log("Old Stream Desroyed");
|
||||
// delete tempStorage[tempUUID];
|
||||
|
||||
// } else {
|
||||
|
||||
// tempStorage[tempUUID] = currentUUID;
|
||||
// }
|
||||
|
||||
|
||||
if (+start === 0 && +end === 1) {
|
||||
|
||||
const dataCoverted = data.toString("hex");
|
||||
|
||||
let neededData = dataCoverted.substring(0, 4);
|
||||
|
||||
const dataBack = Buffer.from(neededData, "hex");
|
||||
|
||||
res.write(dataBack);
|
||||
//res.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!firstBytesRemoved) {
|
||||
|
||||
const dataCoverted = data.toString("hex");
|
||||
|
||||
let neededData = dataCoverted.substring(differenceStart * 2);
|
||||
|
||||
const dataBack = Buffer.from(neededData, "hex");
|
||||
|
||||
firstBytesRemoved = true;
|
||||
|
||||
//sizeCounter += dataBack.length;
|
||||
|
||||
res.write(dataBack);
|
||||
//res.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
res.write(data);
|
||||
//res.flush();
|
||||
//sizeCounter += data.length;
|
||||
})
|
||||
|
||||
decipher.on("end", () => {
|
||||
//console.log("decipher resolved");
|
||||
res.end();
|
||||
streamsToErrorCatch.forEach((stream) => {
|
||||
stream.destroy();
|
||||
})
|
||||
resolve();
|
||||
})
|
||||
|
||||
@@ -118,6 +32,46 @@ const awaitStreamVideo = (start: number, end:number, differenceStart: number,
|
||||
})
|
||||
})
|
||||
|
||||
readStream.on("close", () => {
|
||||
decipher.destroy();
|
||||
})
|
||||
|
||||
if (+start === 0 && +end === 1) {
|
||||
|
||||
// This is for Safari/iOS, for whatever reason they ask for the
|
||||
// First byte, but if I actually try to return the first byte
|
||||
// It will not work ???, but if I return the first 4 bytes it seems
|
||||
// To work fine.
|
||||
|
||||
decipher.on("data", (data: Buffer | string) => {
|
||||
|
||||
const dataCoverted = data.toString("hex");
|
||||
|
||||
let neededData = dataCoverted.substring(0, 8);
|
||||
|
||||
const dataBack = Buffer.from(neededData, "hex");
|
||||
|
||||
res.write(dataBack);
|
||||
|
||||
resolve();
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
// This is where the differnce start comes into play, as I said before
|
||||
// There will be an offset caused by the 16 block size of AES256.
|
||||
// So if there was an offset we need to skip over those bytes
|
||||
// To make sure it returns the exact position the browser is requesting.
|
||||
// Most browsers will still work fine without this, such as Chrome and Firefox.
|
||||
// But one browser needs to be pampered and fed the exact right bytes in
|
||||
// Order to function correctly, can you guess what browser? If you
|
||||
// Guessed Safari you would be correct.
|
||||
|
||||
const streamSkip = new StreamSkip({skip: differenceStart});
|
||||
|
||||
decipher.pipe(streamSkip).pipe(res);
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import request from "request";
|
||||
import axios from "axios";
|
||||
import { Response, Request } from "express";
|
||||
import { UserInterface } from "../../../models/user";
|
||||
import convertDriveToMongo from "../../../utils/convertDriveToMongo";
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: UserInterface,
|
||||
auth?: boolean,
|
||||
busboy: any,
|
||||
}
|
||||
|
||||
|
||||
const awaitUploadGoogle = (file: any, size: number, axiosBody: any, axiosConfigObj: any, drive: any, req: RequestType, res: Response, allStreamsToErrorCatch: any[]) => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
allStreamsToErrorCatch.forEach((currentStream: any) => {
|
||||
|
||||
currentStream.on("error", (err: Error) => {
|
||||
console.log("req errror", err)
|
||||
reject({
|
||||
message: "Await Stream Input Error",
|
||||
code: 500,
|
||||
error: err
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
axios.post("https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable", axiosBody, axiosConfigObj).then((result) => {
|
||||
|
||||
const URI: any = result.headers.location
|
||||
|
||||
request.post({
|
||||
url: URI,
|
||||
headers: {
|
||||
"Content-Length": size,
|
||||
},
|
||||
body: file
|
||||
}, async function (e, results, b) {
|
||||
if (e) {
|
||||
console.log(e)
|
||||
return;
|
||||
}
|
||||
|
||||
const jsonResults = JSON.parse(results.body)
|
||||
|
||||
const retrievedFile = await drive.files.get({
|
||||
fileId: jsonResults.id,
|
||||
fields: "*"
|
||||
})
|
||||
|
||||
const reqAny: any = req;
|
||||
const uploadedFile = convertDriveToMongo(retrievedFile.data, reqAny.user._id);
|
||||
res.send(uploadedFile)
|
||||
resolve()
|
||||
|
||||
})
|
||||
|
||||
}).catch((err) => {
|
||||
console.log("axios err", err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default awaitUploadGoogle;
|
||||
@@ -21,8 +21,6 @@ const awaitUploadStream = <T>(inputSteam: any, outputStream: any, req: Request,
|
||||
|
||||
req.on("aborted", () => {
|
||||
|
||||
console.log("Upload Request Cancelling...");
|
||||
|
||||
removeChunks(outputStream);
|
||||
})
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@ const awaitUploadStream = <T>(inputSteam: any, outputStream: any, req: Request,
|
||||
|
||||
req.on("aborted", () => {
|
||||
|
||||
console.log("Upload Request Cancelling...");
|
||||
|
||||
removeChunksFS(path);
|
||||
})
|
||||
|
||||
|
||||
@@ -1,18 +1,36 @@
|
||||
import s3 from "../../../db/s3";
|
||||
import s3Personal from "../../../db/S3Personal";
|
||||
|
||||
const awaitUploadStreamS3 = (params: any) => {
|
||||
const awaitUploadStreamS3 = (params: any, personalFile: boolean, s3Data: {id: string, key: string, bucket: string}) => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
s3.upload(params, (err: any, data: any) => {
|
||||
if (personalFile) {
|
||||
|
||||
if (err) {
|
||||
reject("Amazon upload error");
|
||||
}
|
||||
const s3PersonalAuth = s3Personal(s3Data.id, s3Data.key);
|
||||
|
||||
resolve();
|
||||
})
|
||||
s3PersonalAuth.upload(params, (err: any, data: any) => {
|
||||
|
||||
if (err) {
|
||||
console.log("Amazon upload personal err", err)
|
||||
reject("Amazon upload error");
|
||||
}
|
||||
|
||||
resolve();
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
s3.upload(params, (err: any, data: any) => {
|
||||
|
||||
if (err) {
|
||||
console.log("Amazon upload err", err)
|
||||
reject("Amazon upload error");
|
||||
}
|
||||
|
||||
resolve();
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// class CachedSubsriptions {
|
||||
|
||||
// cachedSubscriptionStatuses: any;
|
||||
|
||||
// constructor() {
|
||||
// this.cachedSubscriptionStatuses = {}
|
||||
// }
|
||||
|
||||
// addToCachedSubscriptionStatus = (userID: string) => {
|
||||
// this.cachedSubscriptionStatuses[userID] = true;
|
||||
// console.log("new cached", this.cachedSubscriptionStatuses)
|
||||
// }
|
||||
|
||||
// checkCachedSubscriptionStatus = (userID: string) => {
|
||||
// console.log("cache check", this.cachedSubscriptionStatuses)
|
||||
// return this.cachedSubscriptionStatuses[userID];
|
||||
// }
|
||||
// }
|
||||
|
||||
// export default CachedSubsriptions;
|
||||
|
||||
// const cachedSubscriptionStatuses: any = {};
|
||||
|
||||
// export default cachedSubscriptionStatuses;
|
||||
|
||||
// import redis from "redis";
|
||||
|
||||
// const client = redis.createClient();
|
||||
|
||||
// export const setCachedValue = (userID: string) => {
|
||||
|
||||
// const date = new Date();
|
||||
|
||||
// return new Promise((resolve, reject) => {
|
||||
// client.set(userID, date.getTime().toString(), (err, res) => {
|
||||
// if (err) {
|
||||
// console.log("Redis key err", err);
|
||||
// reject()
|
||||
// }
|
||||
// resolve();
|
||||
// });
|
||||
// })
|
||||
// }
|
||||
|
||||
// export const checkCachedValue = (userID: string) => {
|
||||
|
||||
// return new Promise((resolve, reject) => {
|
||||
// client.get(userID, (err) => {
|
||||
// if (err) {
|
||||
// console.log("Redis key err", err);
|
||||
// reject()
|
||||
// } else {
|
||||
// resolve();
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
@@ -0,0 +1,27 @@
|
||||
import s3Auth from "../../../db/S3Personal";
|
||||
|
||||
const calculateS3Size = async(id:string, key:string, bucket:string) => {
|
||||
|
||||
const s3Storage = s3Auth(id, key);
|
||||
|
||||
const params = {
|
||||
Bucket: bucket
|
||||
}
|
||||
|
||||
const objectList = await s3Storage.listObjects(params).promise();
|
||||
|
||||
if (!objectList.Contents) return 0;
|
||||
|
||||
let size = 0
|
||||
|
||||
for (let i = 0; i < objectList.Contents!.length; i++) {
|
||||
const currentObject = objectList.Contents[i];
|
||||
if (!currentObject.Size) continue;
|
||||
|
||||
size += +currentObject.Size!;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
export default calculateS3Size;
|
||||
@@ -0,0 +1,25 @@
|
||||
import {FileInterface} from "../../../models/file";
|
||||
import {UserInterface} from "../../../models/user";
|
||||
import createThumbnailS3 from "./createThumbnailS3";
|
||||
import createThumbnailMongo from "./createThumbnail";
|
||||
import createThumbnailFilesystem from "./createThumbnailFS";
|
||||
import env from "../../../enviroment/env";
|
||||
|
||||
const createThumnailAny = async(currentFile: FileInterface, filename: string, user: UserInterface) => {
|
||||
|
||||
if (currentFile.metadata.personalFile || env.dbType === "s3") {
|
||||
|
||||
return await createThumbnailS3(currentFile, filename, user);
|
||||
|
||||
} else if (env.dbType === "mongo") {
|
||||
|
||||
return await createThumbnailMongo(currentFile, filename, user);
|
||||
|
||||
} else {
|
||||
|
||||
return await createThumbnailFilesystem(currentFile, filename, user);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default createThumnailAny;
|
||||
@@ -50,7 +50,7 @@ const createThumbnail = (file: FileInterface, filename: string, user: UserInterf
|
||||
await thumbnailModel.save();
|
||||
|
||||
const getUpdatedFile = await conn.db.collection("fs.files")
|
||||
.findOneAndUpdate({"_id": file._id}, {"$set": {"metadata.hasThumbnail": true, "metadata.thumbnailID": thumbnailModel._id}})
|
||||
.findOneAndUpdate({"_id": new ObjectID(file._id)}, {"$set": {"metadata.hasThumbnail": true, "metadata.thumbnailID": thumbnailModel._id}})
|
||||
|
||||
let updatedFile: FileInterface = getUpdatedFile.value;
|
||||
|
||||
|
||||
@@ -7,22 +7,40 @@ import { UserInterface } from "../../../models/user";
|
||||
import uuid from "uuid";
|
||||
import env from "../../../enviroment/env";
|
||||
import s3 from "../../../db/s3";
|
||||
import s3Auth from "../../../db/S3Personal"
|
||||
|
||||
const conn = mongoose.connection;
|
||||
|
||||
const getS3Auth = async (file: FileInterface, user: UserInterface) => {
|
||||
|
||||
if (file.metadata.personalFile) {
|
||||
|
||||
const s3Data = await user.decryptS3Data();
|
||||
//console.log("s3 data", s3Data)
|
||||
return {s3Storage: s3Auth(s3Data.id, s3Data.key), bucket: s3Data.bucket};
|
||||
} else {
|
||||
|
||||
return {s3Storage: s3, bucket: env.s3Bucket};
|
||||
}
|
||||
}
|
||||
|
||||
const createThumbnailS3 = (file: FileInterface, filename: string, user: UserInterface) => {
|
||||
|
||||
return new Promise<FileInterface>((resolve, reject) => {
|
||||
return new Promise<FileInterface>( async(resolve, reject) => {
|
||||
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
let CIPHER_KEY = crypto.createHash('sha256').update(password!).digest()
|
||||
|
||||
const thumbnailFilename = uuid.v4();
|
||||
|
||||
const params: any = {Bucket: env.s3Bucket, Key: file.metadata.s3ID!};
|
||||
|
||||
const readStream = s3.getObject(params).createReadStream();
|
||||
const {s3Storage, bucket} = await getS3Auth(file, user);
|
||||
|
||||
const isPersonalFile = file.metadata.personalFile;
|
||||
|
||||
const params: any = {Bucket: bucket, Key: file.metadata.s3ID!};
|
||||
|
||||
const readStream = s3Storage.getObject(params).createReadStream();
|
||||
|
||||
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, file.metadata.IV);
|
||||
|
||||
@@ -48,19 +66,19 @@ const createThumbnailS3 = (file: FileInterface, filename: string, user: UserInte
|
||||
})
|
||||
|
||||
const paramsWrite: any = {
|
||||
Bucket: env.s3Bucket,
|
||||
Bucket: bucket,
|
||||
Body : readStream.pipe(decipher).pipe(imageResize).pipe(thumbnailCipher),
|
||||
Key : thumbnailFilename
|
||||
};
|
||||
|
||||
s3.upload(paramsWrite, async(err: any, data: any) => {
|
||||
s3Storage.upload(paramsWrite, async(err: any, data: any) => {
|
||||
|
||||
if (err) {
|
||||
console.log("Amazon Upload Error", err);
|
||||
reject("Amazon upload error");
|
||||
}
|
||||
|
||||
const thumbnailModel = new Thumbnail({name: thumbnailFilename, owner: user._id, IV: thumbnailIV, s3ID: thumbnailFilename});
|
||||
const thumbnailModel = new Thumbnail({name: thumbnailFilename, owner: user._id, IV: thumbnailIV, s3ID: thumbnailFilename, personalFile: isPersonalFile});
|
||||
|
||||
await thumbnailModel.save();
|
||||
|
||||
|
||||
@@ -1,18 +1,38 @@
|
||||
import s3 from "../../../db/s3";
|
||||
import s3Auth from "../../../db/S3Personal";
|
||||
import env from "../../../enviroment/env";
|
||||
import {UserInterface} from "../../../models/user"
|
||||
|
||||
const getPrevIV = (start: number, key: string) => {
|
||||
const getPrevIV = (start: number, key: string, isPersonal: boolean, user: UserInterface) => {
|
||||
|
||||
return new Promise<Buffer | string>((resolve, reject) => {
|
||||
return new Promise<Buffer | string>(async(resolve, reject) => {
|
||||
|
||||
const params: any = {Bucket: env.s3Bucket, Key: key, Range: `bytes=${start}-${start + 15}`};
|
||||
if (isPersonal) {
|
||||
|
||||
const stream = s3.getObject(params).createReadStream();
|
||||
const s3Data = await user.decryptS3Data();
|
||||
|
||||
stream.on("data", (data) => {
|
||||
const params: any = {Bucket: s3Data.bucket, Key: key, Range: `bytes=${start}-${start + 15}`};
|
||||
|
||||
resolve(data);
|
||||
})
|
||||
const s3Storage = s3Auth(s3Data.id, s3Data.key);
|
||||
|
||||
const stream = s3Storage.getObject(params).createReadStream();
|
||||
|
||||
stream.on("data", (data) => {
|
||||
|
||||
resolve(data);
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
const params: any = {Bucket: env.s3Bucket, Key: key, Range: `bytes=${start}-${start + 15}`};
|
||||
|
||||
const stream = s3.getObject(params).createReadStream();
|
||||
|
||||
stream.on("data", (data) => {
|
||||
|
||||
resolve(data);
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ const removeChunks = async(bucketStream: GridFSBucketWriteStream) => {
|
||||
}
|
||||
|
||||
await dbUtilsFile.removeChunksByID(uploadID);
|
||||
console.log("Upload Request Cancelled, Chunks Removed");
|
||||
|
||||
} catch(e) {
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ const removeChunksFS = (path: string) => {
|
||||
resolve();
|
||||
}
|
||||
|
||||
console.log("File Removed");
|
||||
resolve();
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default removeChunksFS;
|
||||
export default removeChunksFS;
|
||||
module.exports = removeChunksFS;
|
||||
@@ -1,21 +1,21 @@
|
||||
import s3 from "../../../db/s3";
|
||||
//import s3 from "../../../db/s3";
|
||||
|
||||
const removeChunksS3 = (parmas: any) => {
|
||||
const removeChunksS3 = (s3: any, parmas: any) => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
s3.deleteObject(parmas, (err, data) => {
|
||||
s3.deleteObject(parmas, (err: any, data: any) => {
|
||||
|
||||
if (err) {
|
||||
console.log("Could not remove S3 file");
|
||||
reject("Could Not Remove S3 File");
|
||||
}
|
||||
|
||||
console.log("Delete S3 file");
|
||||
resolve();
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export default removeChunksS3;
|
||||
export default removeChunksS3;
|
||||
module.exports = removeChunksS3;
|
||||
@@ -0,0 +1,24 @@
|
||||
import User, {UserInterface} from "../../../models/user";
|
||||
import env from "../../../enviroment/env";
|
||||
|
||||
const subtractFromStorageSize = async(userID: string, size: number, isPersonalFile: boolean) => {
|
||||
|
||||
const user = await User.findById(userID) as UserInterface;
|
||||
|
||||
if (isPersonalFile) {
|
||||
user.storageDataPersonal!.storageSize = +user.storageDataPersonal!.storageSize! - +size;
|
||||
if (user.storageDataPersonal!.storageSize < 0) user.storageDataPersonal!.storageSize = 0;
|
||||
await user.save();
|
||||
return
|
||||
}
|
||||
|
||||
if (!user.storageData || (!user.storageData.storageSize && !user.storageData.storageLimit)) user.storageData = {storageSize: 0, storageLimit: 0}
|
||||
|
||||
user.storageData!.storageSize = +user.storageData!.storageSize! - +size;
|
||||
|
||||
if (user.storageData?.storageSize! < 0) user.storageData!.storageSize! = 0;
|
||||
|
||||
await user.save();
|
||||
}
|
||||
|
||||
export default subtractFromStorageSize;
|
||||
@@ -10,10 +10,17 @@ import DbUtilFolder from "../../db/utils/folderUtils";
|
||||
import { UserInterface } from "../../models/user";
|
||||
import { FileInterface } from "../../models/file";
|
||||
import tempStorage from "../../tempStorage/tempStorage";
|
||||
import uuid from "uuid";
|
||||
|
||||
const dbUtilsFile = new DbUtilFile();
|
||||
const dbUtilsFolder = new DbUtilFolder();
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
s3Enabled: boolean,
|
||||
}
|
||||
|
||||
|
||||
class MongoFileService {
|
||||
|
||||
@@ -38,10 +45,9 @@ class MongoFileService {
|
||||
if (!file.lastErrorObject.updatedExisting) throw new NotFoundError("Remove Link File Not Found Error")
|
||||
}
|
||||
|
||||
makePublic = async(user: UserInterface, fileID: string) => {
|
||||
makePublic = async(userID: string, fileID: string) => {
|
||||
|
||||
const userID = user._id;
|
||||
const token = await jwt.sign({_id: userID.toString()}, env.password!);
|
||||
const token = jwt.sign({_id: userID.toString()}, env.passwordAccess!);
|
||||
|
||||
const file = await dbUtilsFile.makePublic(fileID, userID, token);
|
||||
|
||||
@@ -66,7 +72,7 @@ class MongoFileService {
|
||||
|
||||
makeOneTimePublic = async(userID: string, fileID: string) => {
|
||||
|
||||
const token = await jwt.sign({_id: userID.toString()}, env.password!);
|
||||
const token = jwt.sign({_id: userID.toString()}, env.passwordAccess!);
|
||||
|
||||
const file = await dbUtilsFile.makeOneTimePublic(fileID, userID, token);
|
||||
|
||||
@@ -107,16 +113,21 @@ class MongoFileService {
|
||||
return {...currentFile, parentName}
|
||||
}
|
||||
|
||||
getQuickList = async(userID: string) => {
|
||||
getQuickList = async(user: userAccessType | UserInterface) => {
|
||||
|
||||
const quickList = await dbUtilsFile.getQuickList(userID);
|
||||
const userID = user._id;
|
||||
const s3Enabled = user.s3Enabled ? true : false;
|
||||
|
||||
const quickList = await dbUtilsFile.getQuickList(userID, s3Enabled);
|
||||
|
||||
if (!quickList) throw new NotFoundError("Quick List Not Found Error");
|
||||
|
||||
return quickList;
|
||||
}
|
||||
|
||||
getList = async(userID: string, query: any) => {
|
||||
getList = async(user: userAccessType | UserInterface, query: any) => {
|
||||
|
||||
const userID = user._id;
|
||||
|
||||
let searchQuery = query.search || "";
|
||||
const parent = query.parent || "/";
|
||||
@@ -125,11 +136,15 @@ class MongoFileService {
|
||||
const startAt = query.startAt || undefined
|
||||
const startAtDate = query.startAtDate || "0"
|
||||
const startAtName = query.startAtName || ""
|
||||
const storageType = query.storageType || undefined;
|
||||
const folderSearch = query.folder_search || undefined;
|
||||
sortBy = sortBySwitch(sortBy)
|
||||
limit = parseInt(limit)
|
||||
|
||||
const s3Enabled = user.s3Enabled ? true : false;
|
||||
|
||||
const queryObj = createQuery(userID, parent, query.sortby,startAt, startAtDate, searchQuery, startAtName)
|
||||
|
||||
const queryObj = createQuery(userID, parent, query.sortby,startAt, startAtDate, searchQuery, s3Enabled ,startAtName, storageType, folderSearch);
|
||||
|
||||
const fileList = await dbUtilsFile.getList(queryObj, sortBy, limit);
|
||||
|
||||
if (!fileList) throw new NotFoundError("File List Not Found");
|
||||
@@ -146,22 +161,24 @@ class MongoFileService {
|
||||
return tempToken;
|
||||
}
|
||||
|
||||
getDownloadTokenVideo = async(user: UserInterface, cookie: string) => {
|
||||
// No longer needed left for reference
|
||||
|
||||
if (!cookie) throw new NotAuthorizedError("Get Download Token Video Cookie Not Authorized Error");
|
||||
// getDownloadTokenVideo = async(user: UserInterface, cookie: string) => {
|
||||
|
||||
const tempToken = await user.generateTempAuthTokenVideo(cookie);
|
||||
// if (!cookie) throw new NotAuthorizedError("Get Download Token Video Cookie Not Authorized Error");
|
||||
|
||||
if (!tempToken) throw new NotAuthorizedError("Get Download Token Video Not Authorized Error");
|
||||
// const tempToken = await user.generateTempAuthTokenVideo(cookie);
|
||||
|
||||
return tempToken;
|
||||
}
|
||||
// if (!tempToken) throw new NotAuthorizedError("Get Download Token Video Not Authorized Error");
|
||||
|
||||
// return tempToken;
|
||||
// }
|
||||
|
||||
removeTempToken = async(user: UserInterface, tempToken: any, currentUUID: string) => {
|
||||
|
||||
const key = user.getEncryptionKey();
|
||||
|
||||
const decoded = await jwt.verify(tempToken, env.password!) as any;
|
||||
const decoded = await jwt.verify(tempToken, env.passwordAccess!) as any;
|
||||
|
||||
const publicKey = decoded.iv;
|
||||
|
||||
|
||||
@@ -4,6 +4,14 @@ import NotFoundError from "../../utils/NotFoundError";
|
||||
import UtilsFile from "../../db/utils/fileUtils";
|
||||
import UtilsFolder from "../../db/utils/folderUtils";
|
||||
import sortBySwitch from "../../utils/sortBySwitchFolder";
|
||||
import { UserInterface } from "../../models/user";
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
s3Enabled: boolean,
|
||||
}
|
||||
|
||||
const utilsFile = new UtilsFile();
|
||||
const utilsFolder = new UtilsFolder();
|
||||
@@ -97,16 +105,24 @@ class FolderService {
|
||||
}
|
||||
}
|
||||
|
||||
getFolderList = async(userID: string, query: any) => {
|
||||
getFolderList = async(user: userAccessType | UserInterface, query: any) => {
|
||||
|
||||
const userID = user._id;
|
||||
|
||||
let searchQuery = query.search || "";
|
||||
const parent = query.parent || "/";
|
||||
let sortBy = query.sortby || "DEFAULT"
|
||||
sortBy = sortBySwitch(sortBy)
|
||||
const type = query.type;
|
||||
const storageType = query.storageType || undefined;
|
||||
const folderSearch = query.folder_search || undefined;
|
||||
const itemType = query.itemType || undefined;
|
||||
sortBy = sortBySwitch(sortBy);
|
||||
|
||||
const s3Enabled = user.s3Enabled ? true : false;
|
||||
|
||||
if (searchQuery.length === 0) {
|
||||
|
||||
const folderList = await utilsFolder.getFolderListByParent(userID, parent, sortBy);
|
||||
const folderList = await utilsFolder.getFolderListByParent(userID, parent, sortBy, s3Enabled, type, storageType, itemType);
|
||||
|
||||
if (!folderList) throw new NotFoundError("Folder List Not Found Error");
|
||||
|
||||
@@ -115,7 +131,7 @@ class FolderService {
|
||||
} else {
|
||||
|
||||
searchQuery = new RegExp(searchQuery, 'i')
|
||||
const folderList = await utilsFolder.getFolderListBySearch(userID, searchQuery, sortBy);
|
||||
const folderList = await utilsFolder.getFolderListBySearch(userID, searchQuery, sortBy, type, parent, storageType, folderSearch, itemType, s3Enabled);
|
||||
|
||||
if (!folderList) throw new NotFoundError("Folder List Not Found Error");
|
||||
|
||||
@@ -130,6 +146,47 @@ class FolderService {
|
||||
if (!folder) throw new NotFoundError("Rename Folder Not Found");
|
||||
}
|
||||
|
||||
getSubfolderFullList = async(user: userAccessType, id: string) => {
|
||||
|
||||
const userID = user._id;
|
||||
|
||||
const folder = await utilsFolder.getFolderInfo(id, userID)
|
||||
|
||||
const subFolders = await this.getFolderList(user, {parent: id}) //folderService.getFolderList(user._id, {parent: id})
|
||||
|
||||
let folderList: any[] = [];
|
||||
|
||||
const rootID = "/"
|
||||
|
||||
let currentID = folder.parent;
|
||||
|
||||
folderList.push({
|
||||
_id: folder._id,
|
||||
parent: folder._id,
|
||||
name: folder.name,
|
||||
subFolders: subFolders
|
||||
})
|
||||
|
||||
while (true) {
|
||||
|
||||
if (rootID === currentID) break;
|
||||
|
||||
const currentFolder = await this.getFolderInfo(userID, currentID);
|
||||
const currentSubFolders = await this.getFolderList(user, {parent: currentFolder._id});
|
||||
|
||||
folderList.splice(0, 0, {
|
||||
_id: currentFolder._id,
|
||||
parent: currentFolder._id,
|
||||
name: currentFolder.name,
|
||||
subFolders: currentSubFolders
|
||||
})
|
||||
|
||||
currentID = currentFolder.parent;
|
||||
}
|
||||
|
||||
return folderList;
|
||||
}
|
||||
|
||||
moveFolder = async(userID: string, folderID: string, parentID: string) => {
|
||||
|
||||
let parentList = ["/"];
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
import { UserInterface } from "../../models/user";
|
||||
import getGoogleAuth from "../../db/googleAuth";
|
||||
import {google} from "googleapis";
|
||||
import convertDriveListToMongoList from "../../utils/convertDriveListToMongoList";
|
||||
import FileService from "../FileService";
|
||||
import sortGoogleMongoList from "../../utils/sortGoogleMongoList";
|
||||
import convertDriveToMongo from "../../utils/convertDriveToMongo";
|
||||
import convertDriveFoldersToMongoFolders from "../../utils/convertDriveFoldersToMongoFolders";
|
||||
import { Response, Request } from "express";
|
||||
import tempStorage from "../../tempStorage/tempStorage";
|
||||
import uuid from "uuid";
|
||||
import getBusboyData from "../ChunkService/utils/getBusboyData";
|
||||
import axios from "axios";
|
||||
import awaitUploadGoogle from "../ChunkService/utils/awaitUploadGoogle";
|
||||
import {googleQueryType} from "../../utils/createQueryGoogle";
|
||||
import GoogleDbFileUtils from "../../db/utils/googleFileUtils";
|
||||
import sortGoogleMongoQuickFiles from "../../utils/sortGoogleMongoQuickFiles";
|
||||
|
||||
const googleDbFileUtils = new GoogleDbFileUtils();
|
||||
|
||||
interface RequestType extends Request {
|
||||
user?: UserInterface,
|
||||
auth?: boolean,
|
||||
busboy: any,
|
||||
}
|
||||
|
||||
const fileService = new FileService();
|
||||
const fields = 'id, name, size, modifiedTime, hasThumbnail, parents, mimeType, thumbnailLink, webViewLink, shared';
|
||||
|
||||
class GoogleFileService {
|
||||
|
||||
constructor() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
getList = async(user: UserInterface, query: googleQueryType) => {
|
||||
|
||||
const files = await googleDbFileUtils.getList(query, user);
|
||||
|
||||
const nextPageToken = files.data.nextPageToken;
|
||||
|
||||
const userID = user._id;
|
||||
|
||||
const convertedFiles = convertDriveListToMongoList(files.data.files, userID, nextPageToken);
|
||||
|
||||
return convertedFiles;
|
||||
}
|
||||
|
||||
getMongoGoogleList = async(user: UserInterface, query: googleQueryType) => {
|
||||
|
||||
const files = await googleDbFileUtils.getList(query, user);
|
||||
|
||||
const nextPageToken = files.data.nextPageToken;
|
||||
|
||||
const userID = user._id;
|
||||
|
||||
const convertedFiles = convertDriveListToMongoList(files.data.files, userID, nextPageToken);
|
||||
|
||||
const fileList = await fileService.getList(user, query);
|
||||
|
||||
const sortedList = sortGoogleMongoList([...convertedFiles, ...fileList], query)
|
||||
|
||||
return sortedList;
|
||||
}
|
||||
|
||||
getFileInfo = async(user: UserInterface, id: string) => {
|
||||
|
||||
const file = await googleDbFileUtils.getFileInfo(id, user);
|
||||
|
||||
const userID = user._id;
|
||||
const convertedFile = convertDriveToMongo(file.data, userID);
|
||||
|
||||
return convertedFile;
|
||||
}
|
||||
|
||||
getGoogleMongoQuickList = async(user: UserInterface) => {
|
||||
|
||||
const files = await googleDbFileUtils.getQuickList(user);
|
||||
|
||||
const userID = user._id
|
||||
const convertedFiles = convertDriveListToMongoList(files.data.files, userID);
|
||||
|
||||
const quickList = await fileService.getQuickList(user);
|
||||
|
||||
const sortedGoogleMongoQuickList = sortGoogleMongoQuickFiles(convertedFiles, quickList);
|
||||
|
||||
return sortedGoogleMongoQuickList;
|
||||
}
|
||||
|
||||
getGoogleMongoSuggestedList = async(user: UserInterface, searchQuery: string) => {
|
||||
|
||||
const {files, folders} = await googleDbFileUtils.getSuggestedList(searchQuery, user);
|
||||
|
||||
const userID = user._id;
|
||||
|
||||
const convertedFiles = convertDriveListToMongoList(files.data.files, userID);
|
||||
const convertedFolders = convertDriveFoldersToMongoFolders(folders.data.files, userID);
|
||||
|
||||
const {fileList: mongoFileList, folderList: mongoFolderList} = await fileService.getSuggestedList(user._id, searchQuery);
|
||||
|
||||
return {
|
||||
folderList: [...mongoFolderList, ...convertedFolders],
|
||||
fileList: [...mongoFileList, ...convertedFiles]
|
||||
}
|
||||
}
|
||||
|
||||
renameFile = async(user: UserInterface, fileID: string, title: string) => {
|
||||
|
||||
await googleDbFileUtils.renameFile(fileID, title, user);
|
||||
}
|
||||
|
||||
removeFile = async(user: UserInterface, fileID: string) => {
|
||||
|
||||
await googleDbFileUtils.removeFile(fileID, user);
|
||||
}
|
||||
|
||||
downloadFile = async(user: UserInterface, fileID: string, res: Response) => {
|
||||
|
||||
const {fileMetadata, drive} = await googleDbFileUtils.getDownloadFileMetadata(fileID, user);
|
||||
|
||||
res.set('Content-Type', 'binary/octet-stream');
|
||||
res.set('Content-Disposition', 'attachment; filename="' + fileMetadata.data.name! + '"');
|
||||
res.set('Content-Length', fileMetadata.data.size!);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
drive.files.get(
|
||||
{fileId: fileID, alt: "media"},
|
||||
{responseType: "stream"},
|
||||
(err, resp) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
resp?.data
|
||||
.on("end", () => {resolve()})
|
||||
.on("error", (err: any) => {
|
||||
console.log(err);
|
||||
reject();
|
||||
})
|
||||
.pipe(res);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
downloadDoc = async(user: UserInterface, fileID: string, res: Response) => {
|
||||
|
||||
const {fileMetadata, drive} = await googleDbFileUtils.getDownloadFileMetadata(fileID, user);
|
||||
|
||||
res.set('Content-Type', 'binary/octet-stream');
|
||||
res.set('Content-Disposition', 'attachment; filename="' + fileMetadata.data.name! + ".pdf" + '"');
|
||||
res.set('Content-Length', fileMetadata.data.size!);
|
||||
|
||||
drive.files.export({
|
||||
fileId: fileID,
|
||||
mimeType: 'application/pdf'
|
||||
}, {
|
||||
responseType: "stream"
|
||||
}, (err, resp) => {
|
||||
|
||||
if (err) {
|
||||
console.log("export err", err);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
resp?.data.pipe(res)
|
||||
})
|
||||
}
|
||||
|
||||
getThumbnail = async(user: UserInterface, fileID: string, res: Response) => {
|
||||
|
||||
const {fileMetadata, drive} = await googleDbFileUtils.getDownloadFileMetadata(fileID, user);
|
||||
|
||||
res.set('Content-Type', 'binary/octet-stream');
|
||||
res.set('Content-Disposition', 'attachment; filename="' + fileMetadata.data.name! + '"');
|
||||
res.set('Content-Length', fileMetadata.data.size!);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
drive.files.get(
|
||||
{fileId: fileID, alt: "media"},
|
||||
{responseType: "stream"},
|
||||
(err, resp) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
resp?.data
|
||||
.on("end", () => {resolve()})
|
||||
.on("error", (err: any) => {
|
||||
console.log(err);
|
||||
reject();
|
||||
})
|
||||
.pipe(res);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getFullThumbnail = async(user: UserInterface, fileID: string, res: Response) => {
|
||||
|
||||
const {fileMetadata, drive} = await googleDbFileUtils.getDownloadFileMetadata(fileID, user);
|
||||
|
||||
res.set('Content-Type', 'binary/octet-stream');
|
||||
res.set('Content-Disposition', 'attachment; filename="' + fileMetadata.data.name! + '"');
|
||||
res.set('Content-Length', fileMetadata.data.size!);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
drive.files.get(
|
||||
{fileId: fileID, alt: "media"},
|
||||
{responseType: "stream"},
|
||||
(err, resp) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
reject()
|
||||
return;
|
||||
}
|
||||
resp?.data
|
||||
.on("end", () => {resolve()})
|
||||
.on("error", (err: any) => {
|
||||
console.log(err);
|
||||
reject();
|
||||
})
|
||||
.pipe(res);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
streamVideo = async(user: UserInterface, fileID: string, tempUUID: string, req: RequestType, res: Response) => {
|
||||
|
||||
const currentUUID = uuid.v4();
|
||||
tempStorage[tempUUID] = currentUUID;
|
||||
|
||||
const {fileMetadata, drive} = await googleDbFileUtils.getDownloadFileMetadata(fileID, user);
|
||||
|
||||
const fileSize = +fileMetadata.data.size!
|
||||
|
||||
const headers = req.headers;
|
||||
|
||||
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
|
||||
|
||||
let head = {
|
||||
'Content-Range': 'bytes ' + start + '-' + end + '/' + fileSize,
|
||||
'Accept-Ranges': 'bytes',
|
||||
'Content-Length': chunksize,
|
||||
'Content-Type': 'video/mp4'}
|
||||
|
||||
res.writeHead(206, head);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
drive.files.get(
|
||||
{fileId: fileID, alt: "media"},
|
||||
{responseType: "stream", headers: {
|
||||
Range: `bytes=${start}-${end}`
|
||||
}},
|
||||
(err, resp) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
resp?.data
|
||||
.on("end", () => {resolve()})
|
||||
.on("error", (err: any) => {
|
||||
console.log(err);
|
||||
reject();
|
||||
})
|
||||
.on("data", () => {
|
||||
if (tempStorage[tempUUID] !== currentUUID) {
|
||||
resp?.data.destroy();
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
.pipe(res);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
uploadFile = async(user: UserInterface, busboy: any, req: RequestType, res: Response) => {
|
||||
|
||||
const streamsToErrorCatch = [req, busboy];
|
||||
|
||||
const {file, filename, formData} = await getBusboyData(busboy);
|
||||
|
||||
let parent = formData.get("parent") || "/"
|
||||
const size = formData.get("size") || ""
|
||||
|
||||
parent = parent === "/" ? "root" : parent;
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
type fileMetadataType = {
|
||||
name?: string,
|
||||
parents?: string[]
|
||||
}
|
||||
|
||||
let fileMetadata: fileMetadataType = {}
|
||||
fileMetadata.name = filename;
|
||||
|
||||
if (parent !== "/") {
|
||||
fileMetadata.parents = [parent]
|
||||
}
|
||||
|
||||
const googleIDandKey = await user.decryptDriveIDandKey();
|
||||
const clientID = googleIDandKey.clientID;
|
||||
const clientKey = googleIDandKey.clientKey;
|
||||
const googleToken = await user.decryptDriveTokenData();
|
||||
const refreshToken = googleToken.refresh_token;
|
||||
|
||||
const data = {
|
||||
client_id: clientID,
|
||||
client_secret: clientKey,
|
||||
refresh_token: refreshToken,
|
||||
grant_type: 'refresh_token'
|
||||
}
|
||||
|
||||
const tokenResp = await axios.post("https://www.googleapis.com/oauth2/v4/token", data);
|
||||
const accessToken = tokenResp.data.access_token
|
||||
|
||||
const config = {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Content-Length': size,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
const axiosConfigObj = {
|
||||
headers: config,
|
||||
}
|
||||
|
||||
const axiosBody = {
|
||||
name: filename,
|
||||
parents: [parent],
|
||||
fields: "*"
|
||||
}
|
||||
|
||||
await awaitUploadGoogle(file, size, axiosBody, axiosConfigObj, drive, req, res, streamsToErrorCatch);
|
||||
|
||||
}
|
||||
|
||||
moveFile = async(user: UserInterface, fileID: string, parentID: string) => {
|
||||
|
||||
await googleDbFileUtils.moveFile(fileID, parentID, user);
|
||||
}
|
||||
|
||||
makeFilePublic = async(user: UserInterface, fileID: string) => {
|
||||
|
||||
const publicURL = await googleDbFileUtils.makeFilePublic(fileID, user);
|
||||
|
||||
return publicURL;
|
||||
}
|
||||
|
||||
removePublicLink = async(user: UserInterface, fileID: string) => {
|
||||
|
||||
await googleDbFileUtils.removePublicLink(fileID, user);
|
||||
}
|
||||
}
|
||||
|
||||
export default GoogleFileService;
|
||||
@@ -0,0 +1,186 @@
|
||||
import { UserInterface } from "../../models/user";
|
||||
import getGoogleAuth from "../../db/googleAuth";
|
||||
import {google} from "googleapis";
|
||||
import convertDriveFoldersToMongoFolders from "../../utils/convertDriveFoldersToMongoFolders";
|
||||
import FolderService from "../FolderService";
|
||||
import sortGoogleMongoFolderList from "../../utils/sortGoogleMongoFolderList";
|
||||
import convertDriveFolderToMongoFolder from "../../utils/convertDriveFolderToMongoFolder";
|
||||
import {googleQueryType} from "../../utils/createQueryGoogle";
|
||||
import GoogleDbFolderUtils from "../../db/utils/googleFolderUtils";
|
||||
|
||||
const googleDbFolderUtils = new GoogleDbFolderUtils();
|
||||
|
||||
const folderService = new FolderService();
|
||||
|
||||
const fields = 'id, name, createdTime, parents, mimeType'
|
||||
|
||||
class GoogleFolderService {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
getList = async(user: UserInterface, query: googleQueryType) => {
|
||||
|
||||
const folders = await googleDbFolderUtils.getList(query, user);
|
||||
|
||||
const userID = user._id;
|
||||
|
||||
const convertedFolders = convertDriveFoldersToMongoFolders(folders.data.files, userID);
|
||||
|
||||
return convertedFolders;
|
||||
}
|
||||
|
||||
getGoogleMongoList = async(user: UserInterface, query: any) => {
|
||||
|
||||
const googleFolderList = await googleDbFolderUtils.getList(query, user);
|
||||
|
||||
const userID = user._id;
|
||||
|
||||
const convertedFolders = convertDriveFoldersToMongoFolders(googleFolderList.data.files, userID);
|
||||
|
||||
const folderList = await folderService.getFolderList(user, query);
|
||||
|
||||
const mongoGoogleList = sortGoogleMongoFolderList([...convertedFolders, ...folderList], query);
|
||||
|
||||
return mongoGoogleList;
|
||||
}
|
||||
|
||||
getInfo = async(user: UserInterface, id: string) => {
|
||||
|
||||
const folder = await googleDbFolderUtils.getInfo(id, user);
|
||||
|
||||
const userID = user._id;
|
||||
|
||||
const convertedFolder = convertDriveFolderToMongoFolder(folder.data, userID);
|
||||
|
||||
return convertedFolder;
|
||||
}
|
||||
|
||||
getSubFolderList = async(user: UserInterface, id: string) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
const file = await drive.files.get({fileId: id, fields: fields});
|
||||
|
||||
let folderIDList = []
|
||||
let folderNameList = []
|
||||
|
||||
folderIDList.push("/");
|
||||
folderNameList.push("Home")
|
||||
|
||||
const rootGet = await drive.files.get({fileId: "root"});
|
||||
const rootID = rootGet.data.id!;
|
||||
|
||||
let currentID = file.data.parents![0]
|
||||
|
||||
while (true) {
|
||||
|
||||
if (rootID === currentID) break;
|
||||
|
||||
const currentFile = await drive.files.get({fileId: currentID, fields: fields});
|
||||
|
||||
folderIDList.splice(1, 0, currentFile.data.id!)
|
||||
folderNameList.splice(1,0, currentFile.data.name!)
|
||||
|
||||
currentID = currentFile.data.parents![0];
|
||||
}
|
||||
|
||||
folderIDList.push(id);
|
||||
folderNameList.push(file.data.name)
|
||||
|
||||
return {
|
||||
folderIDList,
|
||||
folderNameList
|
||||
}
|
||||
}
|
||||
|
||||
getSubFolderFullList = async(user: UserInterface, id: string) => {
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
const file = await drive.files.get({fileId: id, fields: fields});
|
||||
|
||||
const parent = file.data.parents![0];
|
||||
let queryBuilder = `mimeType = "application/vnd.google-apps.folder"`
|
||||
queryBuilder += ` and "${file.data.id!}" in parents`
|
||||
|
||||
const subFolders = await drive.files.list({fields: `files(${fields})`, q: queryBuilder})
|
||||
|
||||
|
||||
const convertedFile = convertDriveFolderToMongoFolder(file.data, user._id);
|
||||
const convertedSubFolders = convertDriveFoldersToMongoFolders(subFolders.data.files, user._id)
|
||||
|
||||
let folderList: any[] = [];
|
||||
|
||||
const rootGet = await drive.files.get({fileId: 'root', fields: fields});
|
||||
const rootID = rootGet.data.id!;
|
||||
|
||||
let currentID = file.data.parents![0]
|
||||
|
||||
folderList.push({
|
||||
_id: convertedFile._id,
|
||||
parent: convertedFile._id,
|
||||
name: convertedFile.name,
|
||||
subFolders: convertedSubFolders
|
||||
})
|
||||
|
||||
while (true) {
|
||||
|
||||
if (rootID === currentID) break;
|
||||
|
||||
const currentFile = await drive.files.get({fileId: currentID, fields: fields});
|
||||
const currentConvertedFile = convertDriveFolderToMongoFolder(currentFile.data, user._id)
|
||||
|
||||
queryBuilder = `mimeType = "application/vnd.google-apps.folder"`
|
||||
queryBuilder += ` and "${currentConvertedFile._id}" in parents`
|
||||
|
||||
const currentSubFolders = await drive.files.list({fields: `files(${fields})`, q: queryBuilder})
|
||||
const currentConvertedSubFolders = convertDriveFoldersToMongoFolders(currentSubFolders.data.files, user._id)
|
||||
|
||||
folderList.splice(0, 0, {
|
||||
_id: currentConvertedFile._id,
|
||||
parent: currentConvertedFile._id,
|
||||
name: currentConvertedFile.name,
|
||||
subFolders: currentConvertedSubFolders
|
||||
})
|
||||
|
||||
currentID = currentFile.data.parents![0];
|
||||
}
|
||||
|
||||
return folderList;
|
||||
}
|
||||
|
||||
renameFolder = async(user: UserInterface, folderID: string, title: string) => {
|
||||
|
||||
await googleDbFolderUtils.renameFolder(folderID, title, user);
|
||||
}
|
||||
|
||||
removeFolder = async(user: UserInterface, folderID: string) => {
|
||||
|
||||
await googleDbFolderUtils.removeFolder(folderID, user);
|
||||
}
|
||||
|
||||
upload = async(user: UserInterface, name: string, parent: string) => {
|
||||
|
||||
const createdFolder = await googleDbFolderUtils.uploadFolder(name, parent, user);
|
||||
|
||||
const userID = user._id;
|
||||
|
||||
const convertedFolder = convertDriveFolderToMongoFolder(createdFolder.data, userID)
|
||||
|
||||
return convertedFolder;
|
||||
}
|
||||
|
||||
moveFolder = async(user: UserInterface, fileID: string, parentID: string) => {
|
||||
|
||||
await googleDbFolderUtils.moveFolder(fileID, parentID, user);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default GoogleFolderService;
|
||||
@@ -0,0 +1,76 @@
|
||||
import {UserInterface} from "../../models/user";
|
||||
import env from "../../enviroment/env";
|
||||
import { google } from "googleapis";
|
||||
|
||||
class UserGoogleService {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
createGoogleStorageURL = async(user: UserInterface, googleData: any) => {
|
||||
|
||||
const {clientID, clientKey, clientRedirect} = googleData;
|
||||
|
||||
const oauth2Client = new google.auth.OAuth2(
|
||||
clientID, clientKey, env.remoteURL + "/add-google-account"
|
||||
);
|
||||
const url = oauth2Client.generateAuthUrl({
|
||||
access_type: 'offline',
|
||||
prompt: "consent",
|
||||
scope: ["https://www.googleapis.com/auth/drive"],
|
||||
});
|
||||
|
||||
await user.encryptDriveIDandKey(clientID, clientKey);
|
||||
user.decryptDriveIDandKey();
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
addGoogleStorage = async(user: UserInterface, code: string, uuid: string | undefined) => {
|
||||
|
||||
const redirectURL = env.remoteURL + "/add-google-account";
|
||||
|
||||
const decrypyedIdandKey = await user.decryptDriveIDandKey();
|
||||
|
||||
const clientID = decrypyedIdandKey.clientID;
|
||||
const clientKey = decrypyedIdandKey.clientKey
|
||||
|
||||
const oauth2Client = new google.auth.OAuth2(
|
||||
clientID,
|
||||
clientKey,
|
||||
redirectURL,
|
||||
);
|
||||
|
||||
return new Promise<{accessToken: string, refreshToken: string}>((resolve, reject) => {
|
||||
oauth2Client.getToken(code, async(err, tokens) => {
|
||||
|
||||
if (!err) {
|
||||
|
||||
const token: any = tokens;
|
||||
|
||||
user.encryptDriveTokenData(token);
|
||||
|
||||
const {accessToken, refreshToken} = await user.generateAuthToken(uuid);
|
||||
|
||||
resolve({accessToken, refreshToken});
|
||||
|
||||
} else {
|
||||
reject("Get Google Token Error")
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
removeGoogleStorage = async(user: UserInterface, uuid: string | undefined) => {
|
||||
|
||||
user.googleDriveEnabled = undefined;
|
||||
user.googleDriveData = undefined;
|
||||
|
||||
await user.save();
|
||||
|
||||
return await user.generateAuthToken(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
export default UserGoogleService;
|
||||
@@ -0,0 +1,153 @@
|
||||
import {UserInterface} from "../../models/user";
|
||||
import File, { FileInterface } from "../../models/file";
|
||||
import Folder, { FolderInterface } from "../../models/folder";
|
||||
import Thumbnail, { ThumbnailInterface } from "../../models/thumbnail";
|
||||
import { ObjectID } from "mongodb";;
|
||||
import calculateS3Size from "../ChunkService/utils/calculateS3Size";
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
s3Enabled: boolean,
|
||||
}
|
||||
|
||||
class UserPeronsalService {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
addS3Storage = async(user: UserInterface, s3Data: any, uuid: string | undefined) => {
|
||||
|
||||
const {id, key, bucket} = s3Data;
|
||||
|
||||
user.storageDataPersonal!.storageSize = await calculateS3Size(id, key, bucket);
|
||||
user.personalStorageCanceledDate = undefined;
|
||||
|
||||
await user.encryptS3Data(id, key, bucket);
|
||||
|
||||
await user.save();
|
||||
|
||||
return await user.generateAuthToken(uuid);
|
||||
}
|
||||
|
||||
removeS3Storage = async(user: UserInterface, uuid: string | undefined) => {
|
||||
|
||||
const date = new Date();
|
||||
|
||||
user.s3Enabled = undefined;
|
||||
user.s3Data = undefined;
|
||||
user.storageDataPersonal = undefined;
|
||||
user.personalStorageCanceledDate = date.getTime();
|
||||
|
||||
await user.save();
|
||||
|
||||
return await user.generateAuthToken(uuid);
|
||||
}
|
||||
|
||||
downloadPersonalFileList = async(user: userAccessType) => {
|
||||
|
||||
const fileList = await File.find({"metadata.owner": new ObjectID(user._id), "metadata.personalFile": true});
|
||||
|
||||
const folderList = await Folder.find({"owner": user._id.toString(), 'personalFolder': true});
|
||||
|
||||
const thumbnailList: ThumbnailInterface[] = [];
|
||||
|
||||
for (const currentFile of fileList) {
|
||||
|
||||
if (currentFile.metadata.hasThumbnail) {
|
||||
|
||||
const currentThumbnail = await Thumbnail.findById(new ObjectID(currentFile.metadata.thumbnailID)) as ThumbnailInterface;
|
||||
thumbnailList.push(currentThumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
const combined = {fileList, folderList, thumbnailList}
|
||||
|
||||
const data = JSON.stringify(combined);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
uploadPersonalFileList = async(user: userAccessType, data: any) => {
|
||||
|
||||
const personalFileList: FileInterface[] = data.fileList;
|
||||
const personalFolderList: FolderInterface[] = data.folderList;
|
||||
const personalThumbnailList: ThumbnailInterface[] = data.thumbnailList;
|
||||
|
||||
const fixedFileList: FileInterface[] = []
|
||||
|
||||
for (let currentObj of personalFileList) {
|
||||
|
||||
await File.deleteMany({_id: new ObjectID(currentObj._id), 'metadata.owner': new ObjectID(user._id)});
|
||||
|
||||
currentObj.metadata.owner = new ObjectID(user._id);
|
||||
currentObj._id = new ObjectID(currentObj._id)
|
||||
const oldIV: any = currentObj.metadata.IV;
|
||||
const IV: any = Buffer.from(oldIV, 'base64');
|
||||
currentObj.metadata.IV = IV;
|
||||
const newDate: any = new Date(currentObj.uploadDate);
|
||||
currentObj.uploadDate = newDate;
|
||||
currentObj.metadata.parent = currentObj.metadata.parent.toString();
|
||||
fixedFileList.push(currentObj);
|
||||
|
||||
}
|
||||
|
||||
const fixedFolderList: FolderInterface[] = []
|
||||
|
||||
for (let currentObj of personalFolderList) {
|
||||
|
||||
await Folder.deleteMany({_id: new ObjectID(currentObj._id), owner: user._id.toString()});
|
||||
|
||||
currentObj._id = new ObjectID(currentObj._id)
|
||||
currentObj.owner = user._id.toString();
|
||||
currentObj.createdAt = new Date(currentObj.createdAt);
|
||||
currentObj.updatedAt = new Date(currentObj.updatedAt);
|
||||
fixedFolderList.push(currentObj);
|
||||
}
|
||||
|
||||
const fixedThumbnailList: ThumbnailInterface[] = [];
|
||||
|
||||
for (let currentObj of personalThumbnailList) {
|
||||
|
||||
await Thumbnail.deleteMany({_id: new ObjectID(currentObj._id), owner: user._id.toString()});
|
||||
|
||||
currentObj._id = new ObjectID(currentObj._id);
|
||||
currentObj.owner = user._id.toString();
|
||||
currentObj.createdAt = new Date(currentObj.createdAt);
|
||||
currentObj.updatedAt = new Date(currentObj.updatedAt);
|
||||
const oldIV: any = currentObj.IV;
|
||||
const IV: any = Buffer.from(oldIV, 'base64');
|
||||
currentObj.IV = IV;
|
||||
fixedThumbnailList.push(currentObj);
|
||||
}
|
||||
|
||||
await File.insertMany(fixedFileList);
|
||||
await Folder.insertMany(fixedFolderList);
|
||||
await Thumbnail.insertMany(fixedThumbnailList);
|
||||
|
||||
}
|
||||
|
||||
removeS3Metadata = async(user: userAccessType) => {
|
||||
|
||||
const fileList = await File.find({"metadata.owner": new ObjectID(user._id),
|
||||
"metadata.personalFile": true})
|
||||
|
||||
for (let currentFile of fileList) {
|
||||
|
||||
await File.deleteOne({_id: new ObjectID(currentFile._id)});
|
||||
await File.deleteOne({_id: currentFile._id});
|
||||
|
||||
if (currentFile.metadata.hasThumbnail) {
|
||||
|
||||
await Thumbnail.deleteOne({_id: new ObjectID(currentFile.metadata.thumbnailID)})
|
||||
await Thumbnail.deleteOne({_id: currentFile.metadata.thumbnailID})
|
||||
}
|
||||
}
|
||||
|
||||
await Folder.deleteMany({'owner': user._id.toString(), 'personalFolder': true});
|
||||
}
|
||||
}
|
||||
|
||||
export default UserPeronsalService;
|
||||
@@ -2,78 +2,124 @@ import User, {UserInterface} from "../../models/user";
|
||||
import bcrypt from "bcrypt";
|
||||
import NotFoundError from "../../utils/NotFoundError";
|
||||
import InternalServerError from "../../utils/InternalServerError";
|
||||
import NotAuthorizedError from "../../utils/NotAuthorizedError";
|
||||
import sendEmailVerification from "../../utils/sendVerificationEmail";
|
||||
import File from "../../models/file";
|
||||
import env from "../../enviroment/env";
|
||||
import getGoogleAuth from "../../db/googleAuth";
|
||||
import { google } from "googleapis";
|
||||
import jwt from "jsonwebtoken"
|
||||
import sendVerificationEmail from "../../utils/sendVerificationEmail";
|
||||
import sendPasswordResetEmail from "../../utils/sendPasswordResetEmail";
|
||||
import ForbiddenError from "../../utils/ForbiddenError";
|
||||
|
||||
type UserDataType = {
|
||||
email: string,
|
||||
password: string,
|
||||
}
|
||||
|
||||
type jwtType = {
|
||||
iv: Buffer,
|
||||
_id: string,
|
||||
}
|
||||
|
||||
|
||||
const uknownUserType = User as unknown;
|
||||
|
||||
const UserStaticType = uknownUserType as {
|
||||
findByCreds: (email: string, password: string) => Promise<UserInterface>;
|
||||
};
|
||||
|
||||
|
||||
class UserService {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
login = async(userData: UserDataType) => {
|
||||
login = async(userData: UserDataType, uuid: string | undefined) => {
|
||||
|
||||
const email = userData.email;
|
||||
const password = userData.password;
|
||||
|
||||
const user = await UserStaticType.findByCreds(email, password);
|
||||
|
||||
const token = await user.generateAuthToken();
|
||||
if (!user) throw new NotFoundError("Cannot Find User");
|
||||
|
||||
if (!user || !token) throw new NotFoundError("Login User Not Found Error");
|
||||
const {accessToken, refreshToken} = await user.generateAuthToken(uuid);
|
||||
|
||||
return {user, token}
|
||||
if (!accessToken || !refreshToken) throw new NotFoundError("Login User Not Found Error");
|
||||
|
||||
return {user, accessToken, refreshToken}
|
||||
}
|
||||
|
||||
logout = async(user: UserInterface, userToken: any) => {
|
||||
logout = async(userID: string, refreshToken: string) => {
|
||||
|
||||
user.tokens = user.tokens.filter((token) => {
|
||||
return token.token !== userToken;
|
||||
})
|
||||
const user = await User.findById(userID);
|
||||
|
||||
if (!user) throw new NotFoundError("Could Not Find User");
|
||||
|
||||
if (refreshToken) {
|
||||
const decoded = jwt.verify(refreshToken, env.passwordRefresh!) as jwtType;
|
||||
const encrpytionKey = user.getEncryptionKey();
|
||||
const encryptedToken = user.encryptToken(refreshToken, encrpytionKey, decoded.iv);
|
||||
|
||||
for (let i = 0; i < user.tokens.length; i++) {
|
||||
|
||||
const currentEncryptedToken = user.tokens[i].token;
|
||||
|
||||
if (currentEncryptedToken === encryptedToken) {
|
||||
|
||||
user.tokens.splice(i, 1);
|
||||
await user.save();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await user.save();
|
||||
}
|
||||
|
||||
logoutAll = async(user: UserInterface) => {
|
||||
logoutAll = async(userID: string) => {
|
||||
|
||||
user.tokens = []
|
||||
const user = await User.findById(userID);
|
||||
|
||||
if (!user) throw new NotFoundError("Could Not Find User");
|
||||
|
||||
user.tokens = [];
|
||||
user.tempTokens = [];
|
||||
|
||||
await user.save();
|
||||
}
|
||||
|
||||
create = async(userData: any) => {
|
||||
create = async(userData: any, uuid: string | undefined) => {
|
||||
|
||||
console.log("Create");
|
||||
|
||||
const user = new User(userData);
|
||||
const user = new User({email: userData.email, password: userData.password, emailVerified: env.disableEmailVerification});
|
||||
await user.save();
|
||||
|
||||
if (!user) throw new NotFoundError("User Not Found");
|
||||
|
||||
await user.generateEncryptionKeys();
|
||||
|
||||
const token = await user.generateAuthToken();
|
||||
const {accessToken, refreshToken} = await user.generateAuthToken(uuid);
|
||||
const emailToken = await user.generateEmailVerifyToken();
|
||||
|
||||
if (!user || !token) throw new InternalServerError("Could Not Create New User Error");
|
||||
if (!env.disableEmailVerification) await sendEmailVerification(user, emailToken);
|
||||
|
||||
return {user, token}
|
||||
if (!accessToken || !refreshToken) throw new InternalServerError("Could Not Create New User Error");
|
||||
|
||||
return {user, accessToken, refreshToken}
|
||||
}
|
||||
|
||||
changePassword = async(user: UserInterface, oldPassword: string, newPassword: string) => {
|
||||
changePassword = async(userID: string, oldPassword: string, newPassword: string, oldRefreshToken: string, uuid: string | undefined) => {
|
||||
|
||||
const user = await User.findById(userID);
|
||||
|
||||
if (!user) throw new NotFoundError("Could Not Find User");
|
||||
|
||||
const date = new Date();
|
||||
|
||||
const isMatch = await bcrypt.compare(oldPassword, user.password);
|
||||
|
||||
if (!isMatch) throw new NotAuthorizedError("Change Passwords Do Not Match Error");
|
||||
if (!isMatch) throw new ForbiddenError("Change Passwords Do Not Match Error");
|
||||
|
||||
const encryptionKey = user.getEncryptionKey();
|
||||
|
||||
@@ -81,15 +127,173 @@ class UserService {
|
||||
|
||||
user.tokens = [];
|
||||
user.tempTokens = [];
|
||||
|
||||
user.passwordLastModified = date.getTime();
|
||||
|
||||
await user.save();
|
||||
await user.changeEncryptionKey(encryptionKey!);
|
||||
|
||||
const newToken = await user.generateAuthToken();
|
||||
const {accessToken, refreshToken} = await user.generateAuthToken(uuid);
|
||||
|
||||
return newToken;
|
||||
return {accessToken, refreshToken};
|
||||
}
|
||||
|
||||
refreshStorageSize = async(userID: string) => {
|
||||
|
||||
const user = await User.findById(userID);
|
||||
|
||||
if (!user) throw new NotFoundError("Cannot find user");
|
||||
|
||||
const fileList = await File.find({"metadata.owner": user._id, "metadata.personalFile": null});
|
||||
|
||||
let size = 0;
|
||||
|
||||
for (let currentFile of fileList) {
|
||||
|
||||
size += currentFile.length;
|
||||
}
|
||||
|
||||
user.storageData = {storageSize: size, storageLimit: 0};
|
||||
|
||||
await user.save();
|
||||
}
|
||||
|
||||
getUserDetailed = async(userID: string) => {
|
||||
|
||||
const user = await User.findById(userID);
|
||||
|
||||
if (!user) throw new NotFoundError("Cannot find user");
|
||||
|
||||
if (user.s3Enabled) {
|
||||
|
||||
try {
|
||||
const {bucket} = await user.decryptS3Data()
|
||||
user.s3Data!.bucket = bucket;
|
||||
} catch (e) {
|
||||
console.log("getting s3 storage data error");
|
||||
user.storageDataPersonal = {storageSize: 0, failed: true}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (user.googleDriveEnabled) {
|
||||
|
||||
try {
|
||||
|
||||
const {clientID} = await user.decryptDriveIDandKey()
|
||||
|
||||
const oauth2Client = await getGoogleAuth(user);
|
||||
const drive = google.drive({version:"v3", auth: oauth2Client});
|
||||
|
||||
const googleData = await drive.about.get({
|
||||
fields: "storageQuota"
|
||||
})
|
||||
|
||||
user.storageDataGoogle = {storageLimit: +googleData.data.storageQuota!.limit!, storageSize: +googleData.data.storageQuota!.usage!}
|
||||
user.googleDriveData!.id = clientID;
|
||||
|
||||
} catch (e) {
|
||||
|
||||
user.storageDataGoogle = {storageLimit: 0, storageSize: 0, failed: true}
|
||||
console.log("get google drive storage data error", e.message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!user.storageData || (!user.storageData.storageSize && !user.storageData.storageLimit)) user.storageData = {storageLimit: 0, storageSize: 0}
|
||||
if (!user.storageDataPersonal || (!user.storageDataPersonal.storageSize && !user.storageDataPersonal.failed)) user.storageDataPersonal = {storageSize: 0}
|
||||
if (!user.storageDataGoogle || (!user.storageDataGoogle.storageLimit && !user.storageDataGoogle.storageSize && !user.storageDataGoogle.failed)) user.storageDataGoogle = {storageLimit: 0, storageSize: 0}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
verifyEmail = async(verifyToken: any) => {
|
||||
|
||||
const decoded: any = jwt.verify(verifyToken!, env.passwordAccess!);
|
||||
|
||||
const iv = decoded.iv;
|
||||
|
||||
const user = await User.findOne({_id: decoded._id}) as UserInterface;
|
||||
const encrpytionKey = user.getEncryptionKey();
|
||||
const encryptedToken = user.encryptToken(verifyToken, encrpytionKey, iv);
|
||||
|
||||
if (encryptedToken === user.emailToken) {
|
||||
user.emailVerified = true;
|
||||
await user.save();
|
||||
return user;
|
||||
|
||||
} else {
|
||||
throw new ForbiddenError('Email Token Verification Failed')
|
||||
}
|
||||
}
|
||||
|
||||
resendVerifyEmail = async(userID: string) => {
|
||||
|
||||
const user = await User.findById(userID);
|
||||
|
||||
if (!user) throw new NotFoundError("Cannot find user")
|
||||
|
||||
const verifiedEmail = user.emailVerified;
|
||||
|
||||
if (!verifiedEmail) {
|
||||
|
||||
const emailToken = await user.generateEmailVerifyToken();
|
||||
await sendVerificationEmail(user, emailToken);
|
||||
|
||||
} else {
|
||||
throw new ForbiddenError("Email Already Authorized")
|
||||
}
|
||||
}
|
||||
|
||||
sendPasswordReset = async(email: string) => {
|
||||
|
||||
const user = await User.findOne({email});
|
||||
|
||||
if (!user) throw new NotFoundError("User Not Found Password Reset Email")
|
||||
|
||||
const passwordResetToken = await user.generatePasswordResetToken();
|
||||
|
||||
await sendPasswordResetEmail(user, passwordResetToken!);
|
||||
}
|
||||
|
||||
resetPassword = async(newPassword: string, verifyToken: any) => {
|
||||
|
||||
const decoded: any = jwt.verify(verifyToken!, env.passwordAccess!);
|
||||
|
||||
const iv = decoded.iv;
|
||||
|
||||
const user = await User.findOne({_id: decoded._id}) as UserInterface;
|
||||
const encrpytionKey = user.getEncryptionKey();
|
||||
const encryptedToken = user.encryptToken(verifyToken, encrpytionKey, iv);
|
||||
|
||||
if (encryptedToken === user.passwordResetToken) {
|
||||
|
||||
const encryptionKey = user.getEncryptionKey();
|
||||
|
||||
user.password = newPassword;
|
||||
|
||||
user.tokens = [];
|
||||
user.tempTokens = [];
|
||||
user.passwordResetToken = undefined;
|
||||
|
||||
await user.save();
|
||||
await user.changeEncryptionKey(encryptionKey!);
|
||||
|
||||
} else {
|
||||
throw new ForbiddenError("Reset Password Token Do Not Match")
|
||||
}
|
||||
}
|
||||
|
||||
addName = async(userID: string, name: string) => {
|
||||
|
||||
if (!name || name.length === 0) throw new ForbiddenError("No name")
|
||||
|
||||
const user = await User.findById(userID);
|
||||
|
||||
if (!user) throw new NotFoundError("Cannot find user")
|
||||
|
||||
user.name = name;
|
||||
await user.save();
|
||||
}
|
||||
}
|
||||
|
||||
export default UserService;
|
||||
@@ -0,0 +1,12 @@
|
||||
class ForbiddenError extends Error {
|
||||
|
||||
code: number;
|
||||
|
||||
constructor(args: any) {
|
||||
super(args);
|
||||
|
||||
this.code = 403;
|
||||
}
|
||||
}
|
||||
|
||||
export default ForbiddenError;
|
||||
@@ -0,0 +1,12 @@
|
||||
class NotEmailVerifiedError extends Error {
|
||||
|
||||
code: number;
|
||||
|
||||
constructor(args: any) {
|
||||
super(args);
|
||||
|
||||
this.code = 404;
|
||||
}
|
||||
}
|
||||
|
||||
export default NotEmailVerifiedError;
|
||||
@@ -0,0 +1,12 @@
|
||||
class NotValidDataError extends Error {
|
||||
|
||||
code: number;
|
||||
|
||||
constructor(args: any) {
|
||||
super(args);
|
||||
|
||||
this.code = 403;
|
||||
}
|
||||
}
|
||||
|
||||
export default NotValidDataError;
|
||||
@@ -0,0 +1,17 @@
|
||||
const convertDriveFolderToMongoFolder = (driveObj: any, ownerID: string) => {
|
||||
|
||||
let convertedObj:any = {};
|
||||
convertedObj._id = driveObj.id;
|
||||
convertedObj.name = driveObj.name;
|
||||
convertedObj.createdAt = driveObj.createdTime;
|
||||
convertedObj.owner = ownerID;
|
||||
convertedObj.parent = driveObj.parents[driveObj.parents.length - 1];
|
||||
convertedObj.parentList = driveObj.parents;
|
||||
convertedObj.updatedAt = driveObj.createdTime;
|
||||
convertedObj.drive = true;
|
||||
convertedObj.googleDoc = driveObj.mimeType === "application/vnd.google-apps.document";
|
||||
|
||||
return convertedObj;
|
||||
}
|
||||
|
||||
export default convertDriveFolderToMongoFolder;
|
||||
@@ -0,0 +1,14 @@
|
||||
import convertDriveFolderToMongoFolder from "./convertDriveFolderToMongoFolder";
|
||||
|
||||
const convertDriveFoldersToMongoFolders = (driveObjs: any, ownerID: string) => {
|
||||
|
||||
let convertedFolders = [];
|
||||
|
||||
for (let currentFolder of driveObjs) {
|
||||
convertedFolders.push(convertDriveFolderToMongoFolder(currentFolder, ownerID))
|
||||
}
|
||||
|
||||
return convertedFolders;
|
||||
}
|
||||
|
||||
export default convertDriveFoldersToMongoFolders;
|
||||
@@ -0,0 +1,14 @@
|
||||
import convertDriveToMongo from "./convertDriveToMongo";
|
||||
|
||||
const convertDriveListToMongoList = (driveObjs: any, ownerID:string, pageToken?: string | null | undefined) => {
|
||||
|
||||
let convertedObjs = [];
|
||||
|
||||
for (let currentObj of driveObjs) {
|
||||
convertedObjs.push(convertDriveToMongo(currentObj, ownerID, pageToken));
|
||||
}
|
||||
|
||||
return convertedObjs;
|
||||
}
|
||||
|
||||
export default convertDriveListToMongoList;
|
||||
@@ -0,0 +1,30 @@
|
||||
import videoChecker from "./videoChecker";
|
||||
import {FileInterface} from "../models/file";
|
||||
|
||||
const convertDriveToMongo = (driveObj: any, ownerID: string, pageToken?: string | undefined | null) => {
|
||||
|
||||
let convertedObj: any = {};
|
||||
convertedObj._id = driveObj.id;
|
||||
convertedObj.filename = driveObj.name;
|
||||
convertedObj.length = driveObj.size;
|
||||
convertedObj.uploadDate = driveObj.modifiedTime;
|
||||
convertedObj.pageToken = pageToken
|
||||
convertedObj.metadata = {
|
||||
IV: "",
|
||||
hasThumbnail: driveObj.hasThumbnail,
|
||||
isVideo: videoChecker(driveObj.name),
|
||||
owner: ownerID,
|
||||
parent: driveObj.parents[driveObj.parents.length - 1] === "root" ? "/" : driveObj.parents[driveObj.parents.length - 1],
|
||||
parentList: driveObj.parents,
|
||||
size: driveObj.size,
|
||||
drive: true,
|
||||
googleDoc: driveObj.mimeType === "application/vnd.google-apps.document",
|
||||
thumbnailID: driveObj.thumbnailLink,
|
||||
link: driveObj.shared ? driveObj.webViewLink : undefined,
|
||||
linkType: driveObj.shared ? "public" : undefined
|
||||
}
|
||||
|
||||
return convertedObj;
|
||||
}
|
||||
|
||||
export default convertDriveToMongo;
|
||||
@@ -1,5 +1,8 @@
|
||||
import s3 from "../db/s3"
|
||||
import { ObjectID } from "mongodb"
|
||||
|
||||
export interface QueryInterface {
|
||||
"metadata.owner": string,
|
||||
"metadata.owner": ObjectID,
|
||||
"metadata.parent"?: string,
|
||||
filename?: string | RegExp | {
|
||||
$lt?: string,
|
||||
@@ -9,11 +12,12 @@ export interface QueryInterface {
|
||||
$lt?: Date,
|
||||
$gt?: Date,
|
||||
},
|
||||
"metadata.personalFile"?: boolean | null
|
||||
}
|
||||
|
||||
const createQuery = (owner: string, parent: string, sortBy: string, startAt: number, startAtDate: number, searchQuery: string | RegExp, startAtName: string) => {
|
||||
const createQuery = (owner: string, parent: string, sortBy: string, startAt: number, startAtDate: number, searchQuery: string | RegExp, s3Enabled: boolean,startAtName: string, storageType: string, folderSearch: boolean) => {
|
||||
|
||||
let query: QueryInterface = {"metadata.owner": owner}
|
||||
let query: QueryInterface = {"metadata.owner": new ObjectID(owner)}
|
||||
|
||||
if (searchQuery !== "") {
|
||||
|
||||
@@ -21,6 +25,9 @@ const createQuery = (owner: string, parent: string, sortBy: string, startAt: num
|
||||
|
||||
query = {...query, filename: searchQuery}
|
||||
|
||||
if (parent !== "/" || folderSearch) query = {...query, "metadata.parent": parent}
|
||||
//if (parent === "home") query = {...query, "metadata.parent": "/"};
|
||||
|
||||
} else {
|
||||
|
||||
query = {...query, "metadata.parent": parent}
|
||||
@@ -46,6 +53,16 @@ const createQuery = (owner: string, parent: string, sortBy: string, startAt: num
|
||||
}
|
||||
}
|
||||
|
||||
// if (s3Enabled) {
|
||||
// query = {...query, "metadata.personalFile": true}
|
||||
// } else
|
||||
if (!s3Enabled) {
|
||||
query = {...query, "metadata.personalFile": null}
|
||||
}
|
||||
|
||||
// if (storageType === "s3") {
|
||||
// query = {...query, "metadata.personalFile": true}
|
||||
// }
|
||||
|
||||
return query;
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
const createQueryGoogle = (query: any, parent: any) => {
|
||||
|
||||
let queryBuilder = `mimeType != "application/vnd.google-apps.folder"`
|
||||
|
||||
let orderBy = ""
|
||||
|
||||
if (query.sortby === "date_desc" || query.sortby === "DEFAULT") {
|
||||
orderBy = "modifiedTime desc"
|
||||
} else if (query.sortby === "date_asc") {
|
||||
orderBy = "modifiedTime asc"
|
||||
} else if (query.sortby === "alp_desc") {
|
||||
orderBy = "name desc"
|
||||
} else {
|
||||
orderBy = "name asc"
|
||||
}
|
||||
|
||||
if (query.search && query.search.length !== 0) {
|
||||
queryBuilder += ` and name contains "${query.search}"`
|
||||
} else {
|
||||
queryBuilder += ` and "${parent}" in parents`
|
||||
}
|
||||
|
||||
queryBuilder += ` and trashed=false`;
|
||||
|
||||
return {queryBuilder, orderBy}
|
||||
}
|
||||
|
||||
export interface googleQueryType {
|
||||
limit: number,
|
||||
parent: string,
|
||||
pageToken: string,
|
||||
}
|
||||
|
||||
export default createQueryGoogle;
|
||||
@@ -0,0 +1,28 @@
|
||||
const createQueryGoogleFolder = (query: any, parent: string) => {
|
||||
|
||||
let orderBy = ""
|
||||
|
||||
if (query.sortby === "date_desc") {
|
||||
orderBy = "modifiedTime desc"
|
||||
} else if (query.sortby === "date_asc") {
|
||||
orderBy = "modifiedTime asc"
|
||||
} else if (query.sortby === "alp_desc") {
|
||||
orderBy = "name desc"
|
||||
} else {
|
||||
orderBy = "name asc"
|
||||
}
|
||||
|
||||
let queryBuilder = `mimeType = "application/vnd.google-apps.folder"`
|
||||
|
||||
if (query.search && query.search.length !== 0) {
|
||||
queryBuilder += ` and name contains "${query.search}"`
|
||||
} else {
|
||||
queryBuilder += ` and "${parent}" in parents`;
|
||||
}
|
||||
|
||||
queryBuilder += ` and trashed=false`;
|
||||
|
||||
return {orderBy, queryBuilder}
|
||||
}
|
||||
|
||||
export default createQueryGoogleFolder;
|
||||
@@ -0,0 +1,31 @@
|
||||
import env from "../enviroment/env";
|
||||
import {UserInterface} from "../models/user"
|
||||
import sgMail from "@sendgrid/mail";
|
||||
|
||||
const sendPasswordResetEmail = async (user: UserInterface, passwordResetToken: string) => {
|
||||
|
||||
if (process.env.NODE_ENV === "test") {
|
||||
return;
|
||||
}
|
||||
|
||||
const apiKey: any = env.sendgridKey;
|
||||
const sendgridEmail:any = env.sendgridEmail;
|
||||
const url = env.remoteURL + `/reset-password/${passwordResetToken}`
|
||||
|
||||
// console.log("send grid api key", apiKey)
|
||||
// console.log("send grid email", sendgridEmail);
|
||||
// console.log("send grid reset url", url)
|
||||
sgMail.setApiKey(apiKey);
|
||||
|
||||
const msg = {
|
||||
to: user.email,
|
||||
from: sendgridEmail,
|
||||
subject: "myDrive Password Reset",
|
||||
text: `Please navigate to the following link to reset your password: ${url}`
|
||||
}
|
||||
|
||||
await sgMail.send(msg);
|
||||
//console.log("Send grid email sent reset");
|
||||
}
|
||||
|
||||
export default sendPasswordResetEmail;
|
||||
@@ -0,0 +1,29 @@
|
||||
import env from "../enviroment/env";
|
||||
import sgMail from "@sendgrid/mail";
|
||||
|
||||
const currentURL = env.remoteURL;
|
||||
|
||||
const sendShareEmail = async (file: any, respient: string) => {
|
||||
|
||||
if (process.env.NODE_ENV === "test") {
|
||||
return;
|
||||
}
|
||||
|
||||
const apiKey: any = env.sendgridKey;
|
||||
const sendgridEmail:any = env.sendgridEmail;
|
||||
|
||||
sgMail.setApiKey(apiKey);
|
||||
|
||||
const fileLink = `${currentURL}/download-page/${file._id}/${file.metadata.link}`
|
||||
|
||||
const msg = {
|
||||
to: respient,
|
||||
from: sendgridEmail,
|
||||
subject: "A File Was Shared With You Through myDrive",
|
||||
text: `Please navigate to the following link to view the file ${fileLink}`
|
||||
}
|
||||
|
||||
await sgMail.send(msg);
|
||||
}
|
||||
|
||||
export default sendShareEmail
|
||||
@@ -0,0 +1,31 @@
|
||||
import env from "../enviroment/env";
|
||||
import {UserInterface} from "../models/user"
|
||||
import sgMail from "@sendgrid/mail";
|
||||
|
||||
const sendVerificationEmail = async (user: UserInterface, emailToken: string) => {
|
||||
|
||||
if (process.env.NODE_ENV === "test") {
|
||||
return;
|
||||
}
|
||||
|
||||
const apiKey: any = env.sendgridKey;
|
||||
const sendgridEmail:any = env.sendgridEmail;
|
||||
const url = env.remoteURL + `/verify-email/${emailToken}`
|
||||
|
||||
// console.log("send grid api key", apiKey)
|
||||
// console.log("send grid email", sendgridEmail);
|
||||
// console.log("send grid verify url", url)
|
||||
sgMail.setApiKey(apiKey);
|
||||
|
||||
const msg = {
|
||||
to: user.email,
|
||||
from: sendgridEmail,
|
||||
subject: "myDrive Email Verification",
|
||||
text: `Please navigate to the following link to verify your email address: ${url}`
|
||||
}
|
||||
|
||||
await sgMail.send(msg);
|
||||
//console.log("Send grid email sent");
|
||||
}
|
||||
|
||||
export default sendVerificationEmail;
|
||||
@@ -0,0 +1,58 @@
|
||||
import { FolderInterface } from "../models/folder";
|
||||
|
||||
const sortGoogleMongoFolderList = (combinedList: FolderInterface[], query: any) => {
|
||||
|
||||
if (query.sortby === "date_desc" || query.sortby === "DEFAULT") {
|
||||
|
||||
combinedList = combinedList.sort((a, b) => {
|
||||
const convertedDateA = new Date(a.createdAt).getTime();
|
||||
const convertedDateB = new Date(b.createdAt).getTime();
|
||||
return convertedDateB - convertedDateA;
|
||||
})
|
||||
} else if (query.sortby === "date_asc") {
|
||||
|
||||
combinedList = combinedList.sort((a, b) => {
|
||||
const convertedDateA = new Date(a.createdAt).getTime();
|
||||
const convertedDateB = new Date(b.createdAt).getTime();
|
||||
return convertedDateA - convertedDateB;
|
||||
})
|
||||
} else if (query.sortby === "alp_desc") {
|
||||
|
||||
combinedList = combinedList.sort((a, b) => {
|
||||
|
||||
const name1 = a.name.toLowerCase();
|
||||
const name2 = b.name.toLowerCase();
|
||||
|
||||
if (name1 > name2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (name2 > name1) {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0;
|
||||
})
|
||||
} else if (query.sortby === "alp_asc") {
|
||||
|
||||
combinedList = combinedList.sort((a, b) => {
|
||||
|
||||
const name1 = a.name.toLowerCase();
|
||||
const name2 = b.name.toLowerCase();
|
||||
|
||||
if (name1 > name2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (name2 > name1) {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 0;
|
||||
})
|
||||
}
|
||||
|
||||
return combinedList;
|
||||
}
|
||||
|
||||
export default sortGoogleMongoFolderList;
|
||||
@@ -0,0 +1,62 @@
|
||||
import { FileInterface } from "../models/file";
|
||||
|
||||
const sortGoogleMongoList = (fileList: FileInterface[], query: any) => {
|
||||
|
||||
let combinedList = fileList;
|
||||
|
||||
if (query.sortby === "date_desc" || query.sortby === "DEFAULT") {
|
||||
|
||||
combinedList = combinedList.sort((a, b) => {
|
||||
const convertedDateA = new Date(a.uploadDate).getTime();
|
||||
const convertedDateB = new Date(b.uploadDate).getTime();
|
||||
//onsole.log("data", b.uploadDate, convertedDate)
|
||||
return convertedDateB - convertedDateA;
|
||||
})
|
||||
} else if (query.sortby === "date_asc") {
|
||||
|
||||
combinedList = combinedList.sort((a, b) => {
|
||||
const convertedDateA = new Date(a.uploadDate).getTime();
|
||||
const convertedDateB = new Date(b.uploadDate).getTime();
|
||||
//onsole.log("data", b.uploadDate, convertedDate)
|
||||
return convertedDateA - convertedDateB;
|
||||
})
|
||||
} else if (query.sortby === "alp_desc") {
|
||||
|
||||
combinedList = combinedList.sort((a, b) => {
|
||||
|
||||
const name1 = a.filename.toLowerCase();
|
||||
const name2 = b.filename.toLowerCase();
|
||||
|
||||
if (name1 > name2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (name2 > name1) {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0;
|
||||
})
|
||||
} else if (query.sortby === "alp_asc") {
|
||||
|
||||
combinedList = combinedList.sort((a, b) => {
|
||||
|
||||
const name1 = a.filename.toLowerCase();
|
||||
const name2 = b.filename.toLowerCase();
|
||||
|
||||
if (name1 > name2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (name2 > name1) {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 0;
|
||||
})
|
||||
}
|
||||
|
||||
return combinedList;
|
||||
}
|
||||
|
||||
export default sortGoogleMongoList;
|
||||
@@ -0,0 +1,19 @@
|
||||
const sortGoogleMongoQuickFiles = (convertedFiles: any[], quickList: any[]) => {
|
||||
|
||||
let combinedData = [...convertedFiles, ...quickList]
|
||||
|
||||
combinedData = combinedData.sort((a, b) => {
|
||||
const convertedDateA = new Date(a.uploadDate).getTime();
|
||||
const convertedDateB = new Date(b.uploadDate).getTime();
|
||||
|
||||
return convertedDateB - convertedDateA;
|
||||
})
|
||||
|
||||
if (combinedData.length >= 10) {
|
||||
combinedData = combinedData.slice(0, 10);
|
||||
}
|
||||
|
||||
return combinedData;
|
||||
}
|
||||
|
||||
export default sortGoogleMongoQuickFiles;
|
||||
@@ -0,0 +1,37 @@
|
||||
import User, {UserInterface} from "../models/user";
|
||||
|
||||
import {Request, Response, NextFunction} from "express";
|
||||
import NotFoundError from "./NotFoundError";
|
||||
import { createLoginCookie } from "../cookies/createCookies";
|
||||
|
||||
// interface RequestType extends Request {
|
||||
// user?: userAccessType,
|
||||
// token?: string,
|
||||
// encryptedToken?: string,
|
||||
// }
|
||||
|
||||
type userAccessType = {
|
||||
_id: string,
|
||||
emailVerified: boolean,
|
||||
email: string,
|
||||
botChecked: boolean,
|
||||
}
|
||||
|
||||
const userUpdateCheck = async(res: Response, id: string, uuid: string | undefined) => {
|
||||
|
||||
const updatedUser = await User.findById(id);
|
||||
|
||||
if (!updatedUser) throw new NotFoundError("Cannot find updated user auth");
|
||||
|
||||
if (updatedUser.emailVerified) {
|
||||
|
||||
const {accessToken, refreshToken} = await updatedUser.generateAuthToken(uuid);
|
||||
createLoginCookie(res, accessToken, refreshToken);
|
||||
}
|
||||
|
||||
let strippedUser: userAccessType = {_id: updatedUser._id, emailVerified: updatedUser.emailVerified!, email: updatedUser.email, botChecked: false}
|
||||
|
||||
return strippedUser;
|
||||
}
|
||||
|
||||
export default userUpdateCheck;
|
||||
@@ -0,0 +1,102 @@
|
||||
import express, {Request, Response} from "express";
|
||||
import http from "http";
|
||||
import path from "path";
|
||||
import bodyParser from "body-parser";
|
||||
import fs from "fs";
|
||||
const app = express();
|
||||
|
||||
const getWebUIKey = () => {
|
||||
|
||||
console.log("Starting Server...\n")
|
||||
|
||||
const publicPath = path.join(__dirname, "..", "..", "webUISetup");
|
||||
|
||||
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
|
||||
app.use(express.static(publicPath));
|
||||
app.use(express.json());
|
||||
app.use(bodyParser.json({limit: "50mb"}));
|
||||
app.use(bodyParser.urlencoded({limit: "50mb", extended: true, parameterLimit:50000}))
|
||||
|
||||
app.post("/submit", async(req: Request, res: Response) => {
|
||||
|
||||
console.log("Response")
|
||||
await createConfigFiles(req.body.clientObj, req.body.serverObj);
|
||||
|
||||
res.send();
|
||||
})
|
||||
|
||||
app.get("*", (req: Request, res: Response) => {
|
||||
|
||||
res.sendFile(path.join(publicPath, "index.html"));
|
||||
|
||||
})
|
||||
|
||||
const port = process.env.HTTP_PORT || process.env.PORT || "3000";
|
||||
const url = process.env.DOCKER ? undefined : "localhost";
|
||||
|
||||
const server = http.createServer(app) as any;
|
||||
|
||||
server.listen(port, () => {
|
||||
|
||||
console.log(`\nPlease navigate to http://localhost:${port} to enter setup details\n`)
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
const awaitcreateDir = (path: any) => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
fs.mkdir(path, () => {
|
||||
resolve();
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const awaitWriteFile = (path:string, data:string) => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
fs.writeFile(path, data, async(err:any) => {
|
||||
|
||||
if (err) {
|
||||
console.log("file write error", err);
|
||||
reject();
|
||||
}
|
||||
|
||||
resolve();
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const createConfigFiles = async(clientObj: any, serverObj: any) => {
|
||||
|
||||
await awaitcreateDir("./config")
|
||||
|
||||
let totalClientString = "";
|
||||
let totalServerString = "";
|
||||
|
||||
for (let currentKey in clientObj) {
|
||||
totalClientString += `${currentKey}=${clientObj[currentKey]}\n`
|
||||
}
|
||||
|
||||
for (let currentKey in serverObj) {
|
||||
totalServerString += `${currentKey}=${serverObj[currentKey]}\n`
|
||||
}
|
||||
|
||||
if (serverObj.DOCKER) {
|
||||
const combinedStrings = totalClientString + totalServerString;
|
||||
await awaitWriteFile("./docker-variables.env", combinedStrings);
|
||||
} else {
|
||||
await awaitWriteFile("./.env.production", totalClientString);
|
||||
await awaitWriteFile("./config/prod.env", totalServerString);
|
||||
}
|
||||
|
||||
console.log("File(s) Created");
|
||||
}
|
||||
|
||||
getWebUIKey();
|
||||
|
Before Width: | Height: | Size: 327 KiB |
|
After Width: | Height: | Size: 323 KiB |
|
After Width: | Height: | Size: 304 KiB |
|
Before Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 420 KiB |
|
After Width: | Height: | Size: 953 KiB |
|
Before Width: | Height: | Size: 362 KiB |
|
After Width: | Height: | Size: 9.0 MiB |