Merge pull request #69 from subnub/mydrive-4-upgrade

Mydrive 4 upgrade
This commit is contained in:
subnub
2025-02-25 18:21:38 -05:00
committed by GitHub
2309 changed files with 21270 additions and 170455 deletions
Vendored
BIN
View File
Binary file not shown.
+7
View File
@@ -3,6 +3,10 @@ public/dist/
config/dev.env
config/prod.env
config/test.env
config/.env.development
config/.env.test
config/.env.production
config/.env.test
.env.development
.env.test
.env.production
@@ -19,3 +23,6 @@ package-lock.json
dist/
rds-combined-ca-bundle.pem
docker-variables.env
dist-frontend/
dist-backend/
stats.html
-16
View File
@@ -1,16 +0,0 @@
FROM node:13
WORKDIR /usr/app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build:docker
EXPOSE 8080
EXPOSE 3000
CMD [ "npm", "run", "start"]
+16
View File
@@ -0,0 +1,16 @@
FROM node:20
WORKDIR /usr/app-development
COPY package*.json ./
RUN npm install
COPY . .
# Default Ports
EXPOSE 8080
EXPOSE 3000
EXPOSE 5173
CMD [ "npm", "run", "dev"]
+17
View File
@@ -0,0 +1,17 @@
FROM node:20
WORKDIR /usr/app-production
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Default Ports
EXPOSE 8080
EXPOSE 3000
CMD [ "npm", "run", "start"]
+87
View File
@@ -0,0 +1,87 @@
# Either remove the .example from the end of this filename.
# Or create a new file with the same name, but without the .example extension.
# MongoDB URL: Connection string for your MongoDB database
# example: mongodb://localhost:27017/mydrive
MONGODB_URL=
# Database Type: Choose between "fs" and "s3", this specifies where the files will be stored.
# fs = Filesystem
# s3 = Amazon S3
DB_TYPE=
# If using fs,
# File Storage Directory: The directory where the files will be stored. Must be exact path.
# PATH MUST END IN A SLASH
# Example: /Users/kyle/mydrive/
FS_DIRECTORY=
# If using s3,
# S3 Data: The S3 bucket and key where the files will be stored.
S3_ID=
S3_KEY=
S3_BUCKET=
# Encryiption Key (optional): The encryption key used to encrypt the files.
# DO NOT LOSE OR FORGET THIS KEY AS ALL DATA WILL BE LOST IF YOU LOSE IT.
# If you do not supply a key, the app will instead prompt you to type one into the terminal when you start the server.
KEY=
# Ports (optional): The ports to run the server on.
# HTTP_PORT: Default port is 3000
# HTTPS_PORT: Default port is 8080
HTTP_PORT=
HTTPS_PORT=
# URL (optional): The URL to run the server on.
# Most likely not needed, but useful if you are running docker or such
# And need to bind to 0.0.0.0 instead.
URL=
# Email verifcation (optional): If you want to enable email verification configure as so.
# EMAIL_VERIFICATION=true
# Remote URL: This refers to the URL sent in the verification email: Example https://mydrive-storage.com
# Please navigate to the following link to verify your email address: {REMOTE_URL}/verify
# Should NOT end with a slash
EMAIL_VERIFICATION=
EMAIL_DOMAIN=
EMAIL_ADDRESS=
EMAIL_API_KEY=
EMAIL_HOST=
REMOTE_URL=
# Access tokens, refresh, and cookie
# These should be randomly generated in a secure manner.
# If you lose these tokens, all users will be logged out.
# You can also change these if you want to force all users to be logged out.
# Each token should be a different string.
# Example: sa4hQqJwGFLC1LJk59
PASSWORD_ACCESS=
PASSWORD_REFRESH=
PASSWORD_COOKIE=
# Video thumbnails (optional): If you want to enable video thumbnails, configure as so.
# Video thumbnail generation relies on ffmpeg, please ensure you have it installed.
# VIDEO_THUMBNAILS_ENABLED=true
VIDEO_THUMBNAILS_ENABLED=
# Video thumbnails continued (optional):
# Sometimes generating a video thumbnail will fail with the default method.
# If so you can choose to instead temporarily store the video in a directory, and generate a thumbnail from that.
# WARNING: The file will be temporarily stored in this directory UNENCRYPTED.
# Temp directory example: /Users/kyle/mydrive/temp/
# Temp video thumbnail limit: The maximum size of a video thumbnail in bytes.
# Example: 5000000000
TEMP_DIRECTORY=
TEMP_VIDEO_THUMBNAIL_LIMIT=
# Marks cookie generation as secure (Optional)
# This is recommended and should be enabled if you are running the app on HTTPS.
# SECURE_COOKIES=true
SECURE_COOKIES=
# SSL (Optional): If you want to enable SSL, configure as so.
# SSL=true
# Place your SSL certificate files in the root directory of the project
# With the names: certificate.crt, certificate.key, and certificate.ca-bundle;
SSL=
+87
View File
@@ -0,0 +1,87 @@
# Either remove the .example from the end of this filename.
# Or create a new file with the same name, but without the .example extension.
# MongoDB URL: Connection string for your MongoDB database
# example: mongodb://localhost:27017/mydrive
MONGODB_URL=
# Database Type: Choose between "fs" and "s3", this specifies where the files will be stored.
# fs = Filesystem
# s3 = Amazon S3
DB_TYPE=
# If using fs,
# File Storage Directory: The directory where the files will be stored. Must be exact path.
# PATH MUST END IN A SLASH
# Example: /Users/kyle/mydrive/
FS_DIRECTORY=
# If using s3,
# S3 Data: The S3 bucket and key where the files will be stored.
S3_ID=
S3_KEY=
S3_BUCKET=
# Encryiption Key (optional): The encryption key used to encrypt the files.
# DO NOT LOSE OR FORGET THIS KEY AS ALL DATA WILL BE LOST IF YOU LOSE IT.
# If you do not supply a key, the app will instead prompt you to type one into the terminal when you start the server.
KEY=
# Ports (optional): The ports to run the server on.
# HTTP_PORT: Default port is 3000
# HTTPS_PORT: Default port is 8080
HTTP_PORT=
HTTPS_PORT=
# URL (optional): The URL to run the server on.
# Most likely not needed, but useful if you are running docker or such
# And need to bind to 0.0.0.0 instead.
URL=
# Email verifcation (optional): If you want to enable email verification configure as so.
# EMAIL_VERIFICATION=true
# Remote URL: This refers to the URL sent in the verification email: Example https://mydrive-storage.com
# Please navigate to the following link to verify your email address: {REMOTE_URL}/verify
# Should NOT end with a slash
EMAIL_VERIFICATION=
EMAIL_DOMAIN=
EMAIL_ADDRESS=
EMAIL_API_KEY=
EMAIL_HOST=
REMOTE_URL=
# Access tokens, refresh, and cookie
# These should be randomly generated in a secure manner.
# If you lose these tokens, all users will be logged out.
# You can also change these if you want to force all users to be logged out.
# Each token should be a different string.
# Example: sa4hQqJwGFLC1LJk59
PASSWORD_ACCESS=
PASSWORD_REFRESH=
PASSWORD_COOKIE=
# Video thumbnails (optional): If you want to enable video thumbnails, configure as so.
# Video thumbnail generation relies on ffmpeg, please ensure you have it installed.
# VIDEO_THUMBNAILS_ENABLED=true
VIDEO_THUMBNAILS_ENABLED=
# Video thumbnails continued (optional):
# Sometimes generating a video thumbnail will fail with the default method.
# If so you can choose to instead temporarily store the video in a directory, and generate a thumbnail from that.
# WARNING: The file will be temporarily stored in this directory UNENCRYPTED.
# Temp directory example: /Users/kyle/mydrive/temp/
# Temp video thumbnail limit: The maximum size of a video thumbnail in bytes.
# Example: 5000000000
TEMP_DIRECTORY=
TEMP_VIDEO_THUMBNAIL_LIMIT=
# Marks cookie generation as secure (Optional)
# This is recommended and should be enabled if you are running the app on HTTPS.
# SECURE_COOKIES=true
SECURE_COOKIES=
# SSL (Optional): If you want to enable SSL, configure as so.
# SSL=true
# Place your SSL certificate files in the root directory of the project
# With the names: certificate.crt, certificate.key, and certificate.ca-bundle;
SSL=
+87
View File
@@ -0,0 +1,87 @@
# Either remove the .example from the end of this filename.
# Or create a new file with the same name, but without the .example extension.
# MongoDB URL: Connection string for your MongoDB database
# example: mongodb://localhost:27017/mydrive
MONGODB_URL=
# Database Type: Choose between "fs" and "s3", this specifies where the files will be stored.
# fs = Filesystem
# s3 = Amazon S3
DB_TYPE=
# If using fs,
# File Storage Directory: The directory where the files will be stored. Must be exact path.
# PATH MUST END IN A SLASH
# Example: /Users/kyle/mydrive/
FS_DIRECTORY=
# If using s3,
# S3 Data: The S3 bucket and key where the files will be stored.
S3_ID=
S3_KEY=
S3_BUCKET=
# Encryiption Key (optional): The encryption key used to encrypt the files.
# DO NOT LOSE OR FORGET THIS KEY AS ALL DATA WILL BE LOST IF YOU LOSE IT.
# If you do not supply a key, the app will instead prompt you to type one into the terminal when you start the server.
KEY=
# Ports (optional): The ports to run the server on.
# HTTP_PORT: Default port is 3000
# HTTPS_PORT: Default port is 8080
HTTP_PORT=
HTTPS_PORT=
# URL (optional): The URL to run the server on.
# Most likely not needed, but useful if you are running docker or such
# And need to bind to 0.0.0.0 instead.
URL=
# Email verifcation (optional): If you want to enable email verification configure as so.
# EMAIL_VERIFICATION=true
# Remote URL: This refers to the URL sent in the verification email: Example https://mydrive-storage.com
# Please navigate to the following link to verify your email address: {REMOTE_URL}/verify
# Should NOT end with a slash
EMAIL_VERIFICATION=
EMAIL_DOMAIN=
EMAIL_ADDRESS=
EMAIL_API_KEY=
EMAIL_HOST=
REMOTE_URL=
# Access tokens, refresh, and cookie
# These should be randomly generated in a secure manner.
# If you lose these tokens, all users will be logged out.
# You can also change these if you want to force all users to be logged out.
# Each token should be a different string.
# Example: sa4hQqJwGFLC1LJk59
PASSWORD_ACCESS=
PASSWORD_REFRESH=
PASSWORD_COOKIE=
# Video thumbnails (optional): If you want to enable video thumbnails, configure as so.
# Video thumbnail generation relies on ffmpeg, please ensure you have it installed.
# VIDEO_THUMBNAILS_ENABLED=true
VIDEO_THUMBNAILS_ENABLED=
# Video thumbnails continued (optional):
# Sometimes generating a video thumbnail will fail with the default method.
# If so you can choose to instead temporarily store the video in a directory, and generate a thumbnail from that.
# WARNING: The file will be temporarily stored in this directory UNENCRYPTED.
# Temp directory example: /Users/kyle/mydrive/temp/
# Temp video thumbnail limit: The maximum size of a video thumbnail in bytes.
# Example: 5000000000
TEMP_DIRECTORY=
TEMP_VIDEO_THUMBNAIL_LIMIT=
# Marks cookie generation as secure (Optional)
# This is recommended and should be enabled if you are running the app on HTTPS.
# SECURE_COOKIES=true
SECURE_COOKIES=
# SSL (Optional): If you want to enable SSL, configure as so.
# SSL=true
# Place your SSL certificate files in the root directory of the project
# With the names: certificate.crt, certificate.key, and certificate.ca-bundle;
SSL=
+633
View File
@@ -0,0 +1,633 @@
import { NextFunction, Request, Response } from "express";
import FileService from "../services/file-service/file-service";
import User, { UserInterface } from "../models/user-model";
import {
createStreamVideoCookie,
removeStreamVideoCookie,
} from "../cookies/create-cookies";
import ChunkService from "../services/chunk-service/chunk-service";
import streamToBuffer from "../utils/streamToBuffer";
import NotAuthorizedError from "../utils/NotAuthorizedError";
import { FileListQueryType } from "../types/file-types";
import fs from "fs";
const fileService = new FileService();
type userAccessType = {
_id: string;
emailVerified: boolean;
email: string;
s3Enabled: boolean;
};
export interface RequestTypeFullUser extends Request {
user?: UserInterface;
encryptedToken?: string;
accessTokenStreamVideo?: string;
}
interface RequestType extends Request {
user?: userAccessType;
encryptedToken?: string;
}
class FileController {
chunkService;
constructor() {
this.chunkService = new ChunkService();
}
getThumbnail = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const id = req.params.id;
await this.chunkService.getThumbnail(user, id, res);
} catch (e: unknown) {
next(e);
}
};
getFullThumbnail = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const fileID = req.params.id;
await this.chunkService.getFullThumbnail(user, fileID, res);
} catch (e: unknown) {
next(e);
}
};
uploadFile = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const busboy = req.busboy;
const file = await this.chunkService.uploadFile(user, busboy, req);
res.send(file);
} catch (e: unknown) {
next(e);
}
};
getPublicDownload = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
try {
const ID = req.params.id;
const tempToken = req.params.tempToken;
await this.chunkService.getPublicDownload(ID, tempToken, res);
} catch (e: unknown) {
next(e);
}
};
removeLink = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const id = req.params.id;
const userID = req.user._id;
const file = await fileService.removeLink(userID, id);
res.send(file);
} catch (e) {
next(e);
}
};
makePublic = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const fileID = req.params.id;
const userID = req.user._id;
const { file, token } = await fileService.makePublic(userID, fileID);
res.send({ file, token });
} catch (e) {
next(e);
}
};
getPublicInfo = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
try {
const id = req.params.id;
const tempToken = req.params.tempToken;
const file = await fileService.getPublicInfo(id, tempToken);
res.send(file);
} catch (e) {
next(e);
}
};
makeOneTimePublic = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const id = req.params.id;
const userID = req.user._id;
const { file, token } = await fileService.makeOneTimePublic(userID, id);
res.send({ file, token });
} catch (e) {
next(e);
}
};
getFileInfo = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const fileID = req.params.id;
const userID = req.user._id;
const file = await fileService.getFileInfo(userID, fileID);
res.send(file);
} catch (e) {
next(e);
}
};
getQuickList = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const limit = Number.parseInt(req.query.limit as string) || 20;
const quickList = await fileService.getQuickList(user, limit);
res.send(quickList);
} catch (e) {
next(e);
}
};
getList = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const query = req.query;
const search = (query.search as string) || undefined;
const parent = (query.parent as string) || "/";
const limit = Number.parseInt(query.limit as string) || 50;
const sortBy = (query.sortBy as string) || "date_desc";
const startAtDate = (query.startAtDate as string) || undefined;
const startAtName = (query.startAtName as string) || undefined;
const trashMode = query.trashMode === "true";
const mediaMode = query.mediaMode === "true";
const mediaFilter = (query.mediaFilter as string) || "all";
const queryData: FileListQueryType = {
userID,
search,
parent,
startAtDate,
startAtName,
trashMode,
mediaMode,
sortBy,
mediaFilter,
};
const fileList = await fileService.getList(queryData, sortBy, limit);
res.send(fileList);
} catch (e) {
next(e);
}
};
getDownloadToken = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const tempToken = await fileService.getDownloadToken(user);
res.send({ tempToken });
} catch (e) {
next(e);
}
};
getAccessTokenStreamVideo = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) return;
try {
const user = req.user;
const currentUUID = req.headers.uuid as string;
const streamVideoAccessToken = await user.generateAuthTokenStreamVideo(
currentUUID
);
createStreamVideoCookie(res, streamVideoAccessToken);
res.send();
} catch (e) {
next(e);
}
};
removeStreamVideoAccessToken = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) return;
try {
const userID = req.user._id;
const accessTokenStreamVideo = req.accessTokenStreamVideo!;
if (!accessTokenStreamVideo) {
throw new NotAuthorizedError("No Access Token");
}
await User.updateOne(
{ _id: userID },
{ $pull: { tempTokens: { token: accessTokenStreamVideo } } }
);
removeStreamVideoCookie(res);
res.send();
} catch (e) {
next(e);
}
};
removeTempToken = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const tempToken = req.params.tempToken;
const currentUUID = req.params.uuid;
await fileService.removeTempToken(user, tempToken, currentUUID);
res.send();
} catch (e) {
next(e);
}
};
streamVideo = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const fileID = req.params.id;
const headers = req.headers;
await this.chunkService.streamVideo(user, fileID, headers, res);
} catch (e: unknown) {
next(e);
}
};
streamVideoTest = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const headers = req.headers;
console.log("headers", headers.range);
const fileSize = 26867866;
const range = headers.range!;
const parts = range.replace(/bytes=/, "").split("-");
const start = parseInt(parts[0], 10);
const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
const chunksize = end - start + 1;
const readStream = fs.createReadStream(
"/Users/kylehoell/Developer/myDrive-4/upgrade/old/video.mp4",
{ start, end }
);
const head = {
"Content-Range": "bytes " + start + "-" + end + "/" + fileSize,
"Accept-Ranges": "bytes",
"Content-Length": chunksize,
"Content-Type": "video/mp4",
};
res.writeHead(206, head);
readStream.on("data", (data) => {
res.write(data);
});
readStream.on("end", () => {
res.end();
});
} catch (e: unknown) {
next(e);
}
};
downloadFile = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const fileID = req.params.id;
await this.chunkService.downloadFile(user, fileID, res);
} catch (e: unknown) {
next(e);
}
};
getSuggestedList = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const searchQuery = req.query.search as string;
const trashMode = req.query.trashMode === "true";
const mediaMode = req.query.mediaMode === "true";
const { fileList, folderList } = await fileService.getSuggestedList(
userID,
searchQuery,
trashMode,
mediaMode
);
return res.send({ folderList, fileList });
} catch (e) {
next(e);
}
};
renameFile = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const fileID = req.body.id;
const title = req.body.title;
const userID = req.user._id;
const file = await fileService.renameFile(userID, fileID, title);
res.send(file);
} catch (e) {
next(e);
}
};
moveFile = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const fileID = req.body.id as string;
const userID = req.user._id as string;
const parentID = (req.body.parentID as string) || "/";
const file = await fileService.moveFile(userID, fileID, parentID);
res.send(file);
} catch (e) {
next(e);
}
};
moveMultiFile = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const items = req.body.items;
const parentID = (req.body.parentID as string) || "/";
await fileService.moveMultiFiles(userID, items, parentID);
res.send();
} catch (e) {
next(e);
}
};
trashFile = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const fileID = req.body.id;
const trashedFile = await fileService.trashFile(userID, fileID);
res.send(trashedFile.toObject());
} catch (e) {
next(e);
}
};
restoreFile = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const fileID = req.body.id;
const file = await fileService.restoreFile(userID, fileID);
res.send(file);
} catch (e) {
next(e);
}
};
deleteFile = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const fileID = req.body.id;
await this.chunkService.deleteFile(userID, fileID);
res.send();
} catch (e) {
next(e);
}
};
deleteMulti = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const items = req.body.items;
await this.chunkService.deleteMulti(userID, items);
res.send();
} catch (e) {
next(e);
}
};
trashMulti = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const items = req.body.items;
await fileService.trashMulti(userID, items);
res.send();
} catch (e) {
next(e);
}
};
restoreMulti = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const items = req.body.items;
await fileService.restoreMulti(userID, items);
res.send();
} catch (e) {
next(e);
}
};
}
export default FileController;
-581
View File
@@ -1,581 +0,0 @@
import { Request, Response } from "express";
import FileService from "../services/FileService";
import MongoService from "../services/ChunkService/MongoService";
import FileSystemService from "../services/ChunkService/FileSystemService";
import S3Service from "../services/ChunkService/S3Service";
import User, {UserInterface} from "../models/user";
import sendShareEmail from "../utils/sendShareEmail";
import { createStreamVideoCookie, removeStreamVideoCookie } from "../cookies/createCookies";
const fileService = new FileService()
type userAccessType = {
_id: string,
emailVerified: boolean,
email: string,
s3Enabled: boolean,
}
interface RequestTypeFullUser extends Request {
user?: UserInterface,
encryptedToken?: string,
accessTokenStreamVideo?: string
}
interface RequestType extends Request {
user?: userAccessType,
encryptedToken?: string
}
type ChunkServiceType = MongoService | FileSystemService | S3Service;
class FileController {
chunkService: ChunkServiceType;
constructor(chunkService: ChunkServiceType) {
this.chunkService = chunkService;
}
getThumbnail = async(req: RequestTypeFullUser, res: Response) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const id = req.params.id;
const decryptedThumbnail = await this.chunkService.getThumbnail(user, id);
res.send(decryptedThumbnail);
} catch (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: RequestTypeFullUser, res: Response) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const fileID = req.params.id;
await this.chunkService.getFullThumbnail(user, fileID, res);
} catch (e) {
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: RequestTypeFullUser, res: Response) => {
if (!req.user) {
return
}
try {
const user = req.user;
const busboy = req.busboy;
req.pipe(busboy);
const file = await this.chunkService.uploadFile(user, busboy, req);
res.send(file);
} catch (e) {
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();
}
}
getPublicDownload = async(req: RequestType, res: Response) => {
try {
const ID = req.params.id;
const tempToken = req.params.tempToken;
await this.chunkService.getPublicDownload(ID, tempToken, res);
} catch (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();
}
}
removeLink = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const id = req.params.id;
const userID = req.user._id;
await fileService.removeLink(userID, id)
res.send();
} catch (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();
}
}
makePublic = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const fileID = req.params.id;
const userID = req.user._id;
const token = await fileService.makePublic(userID, fileID);
res.send(token);
} catch (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();
}
}
getPublicInfo = async(req: RequestType, res: Response) => {
try {
const id = req.params.id;
const tempToken = req.params.tempToken;
const file = await fileService.getPublicInfo(id, tempToken);
res.send(file);
} catch (e) {
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();
}
}
makeOneTimePublic = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const id = req.params.id;
const userID = req.user._id;
const token = await fileService.makeOneTimePublic(userID, id);
res.send(token);
} catch (e) {
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();
}
}
getFileInfo = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const fileID = req.params.id;
const userID = req.user._id;
const file = await fileService.getFileInfo(userID, fileID);
res.send(file);
} catch (e) {
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();
}
}
getQuickList = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const quickList = await fileService.getQuickList(user);
res.send(quickList);
} catch (e) {
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();
}
}
getList = async(req: RequestType, res: Response) => {
if (!req.user) {
return
}
try {
const user = req.user;
const query = req.query;
const fileList = await fileService.getList(user, query);
res.send(fileList);
} catch (e) {
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: RequestTypeFullUser, res: Response) => {
if (!req.user) {
return
}
try {
const user = req.user;
const tempToken = await fileService.getDownloadToken(user);
res.send({tempToken});
} catch (e) {
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();
}
}
getAccessTokenStreamVideo = async(req: RequestTypeFullUser, res: Response) => {
if (!req.user) return;
try {
const user = req.user;
const currentUUID = req.headers.uuid as string;
const streamVideoAccessToken = await user.generateAuthTokenStreamVideo(currentUUID);
createStreamVideoCookie(res, streamVideoAccessToken);
res.send();
} catch (e) {
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();
}
}
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();
}
}
// 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
}
try {
const user = req.user
const tempToken = req.params.tempToken;
const currentUUID = req.params.uuid;
await fileService.removeTempToken(user, tempToken, currentUUID);
res.send();
} catch (e) {
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: RequestTypeFullUser, res: Response) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const fileID = req.params.id;
const headers = req.headers;
await this.chunkService.streamVideo(user, fileID, headers, res, req);
} catch (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: RequestTypeFullUser, res: Response) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const fileID = req.params.id;
await this.chunkService.downloadFile(user, fileID, res);
} catch (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();
}
}
getSuggestedList = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
let searchQuery = req.query.search || "";
const {fileList, folderList} = await fileService.getSuggestedList(userID, searchQuery);
return res.send({folderList, fileList})
} catch (e) {
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();
}
}
renameFile = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const fileID = req.body.id;
const title = req.body.title
const userID = req.user._id;
await fileService.renameFile(userID, fileID, title)
res.send();
} catch (e) {
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();
}
}
sendEmailShare = async(req: RequestType, res: Response) => {
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;
}
try {
const fileID = req.body.id;
const userID = req.user._id;
const parentID = req.body.parent;
await fileService.moveFile(userID, fileID, parentID);
res.send();
} catch (e) {
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();
}
}
deleteFile = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const fileID = req.body.id;
await this.chunkService.deleteFile(userID, fileID);
res.send()
} catch (e) {
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();
}
}
}
export default FileController;
+285
View File
@@ -0,0 +1,285 @@
import FolderService from "../services/folder-service/folder-service";
import { NextFunction, Request, Response } from "express";
import ChunkService from "../services/chunk-service/chunk-service";
import { FolderListQueryType } from "../types/folder-types";
import { UserInterface } from "../models/user-model";
const folderService = new FolderService();
type userAccessType = {
_id: string;
emailVerified: boolean;
email: string;
s3Enabled: boolean;
};
interface RequestType extends Request {
user?: userAccessType;
encryptedToken?: string;
}
interface RequestTypeFullUser extends Request {
user?: UserInterface;
encryptedToken?: string;
accessTokenStreamVideo?: string;
}
const chunkService = new ChunkService();
class FolderController {
constructor() {}
createFolder = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const name = req.body.name;
const parent = req.body.parent || "/";
const folder = await folderService.createFolder(userID, name, parent);
res.status(201).send(folder);
} catch (e) {
next(e);
}
};
deleteFolder = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const folderID = req.body.id;
await chunkService.deleteFolder(userID, folderID);
res.send();
} catch (e) {
next(e);
}
};
uploadFolder = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const busboy = req.busboy;
await chunkService.uploadFolder(user, busboy, req);
res.send();
} catch (e) {
next(e);
}
};
deleteAll = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
await chunkService.deleteAll(userID);
res.send();
} catch (e) {
next(e);
}
};
getInfo = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const folderID = req.params.id;
const folder = await folderService.getFolderInfo(userID, folderID);
res.send(folder);
} catch (e) {
next(e);
}
};
getFolderList = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const user = req.user;
const query = req.query;
const search = (query.search as string) || undefined;
const parent = (query.parent as string) || "/";
const sortBy = (query.sortBy as string) || "date_desc";
const trashMode = query.trashMode === "true";
const queryData: FolderListQueryType = {
userID: user._id.toString(),
search,
parent,
trashMode,
};
const folderList = await folderService.getFolderList(queryData, sortBy);
res.send(folderList);
} catch (e) {
next(e);
}
};
moveFolder = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const folderID = req.body.id;
const parentID = req.body.parentID;
const folder = await folderService.moveFolder(userID, folderID, parentID);
res.send(folder);
} catch (e) {
next(e);
}
};
trashFolder = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const folderID = req.body.id;
await folderService.trashFolder(userID, folderID);
res.send();
} catch (e) {
next(e);
}
};
restoreFolder = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const folderID = req.body.id;
await folderService.restoreFolder(userID, folderID);
res.send();
} catch (e) {
next(e);
}
};
renameFolder = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const folderID = req.body.id;
const title = req.body.title;
await folderService.renameFolder(userID, folderID, title);
res.send();
} catch (e) {
next(e);
}
};
downloadZip = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const folderIDs = (req.query.folderIDs as string[]) || [];
const fileIDs = (req.query.fileIDs as string[]) || [];
await chunkService.downloadZip(userID, folderIDs, fileIDs, res);
} catch (e) {
next(e);
}
};
getMoveFolderList = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const parent = (req.query.parent as string) || undefined;
const search = (req.query.search as string) || undefined;
const folderIDs = (req.query.folderIDs as string[]) || [];
const folderList = await folderService.getMoveFolderList(
userID,
parent,
search,
folderIDs
);
res.send(folderList);
} catch (e) {
next(e);
}
};
}
export default FolderController;
-274
View File
@@ -1,274 +0,0 @@
import FolderService from "../services/FolderService";
import { Request, Response } from "express";
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?: userAccessType,
encryptedToken?: string
}
type ChunkServiceType = MongoService | FileSystemService | S3Service;
class FolderController {
chunkService: ChunkServiceType;
constructor(chunkService: ChunkServiceType) {
this.chunkService = chunkService;
}
uploadFolder = async(req: RequestType, res: Response) => {
if (!req.user) {
return
}
try {
const data = req.body;
const folder = await folderService.uploadFolder(data);
res.send(folder);
} catch (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();
}
}
deleteFolder = 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
await this.chunkService.deleteFolder(userID, folderID, parentList);
res.send();
} catch (e) {
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();
}
}
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();
}
}
deleteAll = async(req: RequestType, res: Response) => {
if (!req.user) {
return
}
try {
const userID = req.user._id;
await this.chunkService.deleteAll(userID);
res.send();
} catch (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();
}
}
getInfo = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const folderID = req.params.id;
const folder = await folderService.getFolderInfo(userID, folderID);
res.send(folder);
} catch (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();
}
}
getSubfolderList = async(req: RequestType, res: Response) => {
if (!req.user) {
return
}
try {
const userID = req.user._id;
const folderID = req.query.id as string;
const {folderIDList, folderNameList} = await folderService.getFolderSublist(userID, folderID);
res.send({folderIDList, folderNameList})
} catch (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();
}
}
getFolderList = async(req: RequestType, res: Response) => {
if (!req.user) {
return
}
try {
const user = req.user;
const query = req.query;
const folderList = await folderService.getFolderList(user, query);
res.send(folderList);
} catch (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();
}
}
moveFolder = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const folderID = req.body.id;
const parent = req.body.parent;
await folderService.moveFolder(userID, folderID, parent);
res.send();
} catch (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();
}
}
renameFolder = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const folderID = req.body.id;
const title = req.body.title
await folderService.renameFolder(userID, folderID, title);
res.send()
} catch (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();
}
}
}
export default FolderController;
-384
View File
@@ -1,384 +0,0 @@
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;
-230
View File
@@ -1,230 +0,0 @@
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;
-202
View File
@@ -1,202 +0,0 @@
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;
+43
View File
@@ -0,0 +1,43 @@
import disk from "diskusage";
import env from "../enviroment/env";
import { Request, Response } from "express";
import { UserInterface } from "../models/user-model";
type userAccessType = {
_id: string;
emailVerified: boolean;
email: string;
s3Enabled: boolean;
};
interface RequestType extends Request {
user?: userAccessType;
encryptedToken?: string;
}
class StorageController {
constructor() {}
getStorageInfo = async (req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
if (!env.root || env.root.length === 0) {
return;
}
const info = await disk.check(env.root!);
res.send(info);
} catch (e) {
if (e instanceof Error) {
console.log("\nGet Storage Error Storage Route:", e.message);
}
res.status(500).send("Server error getting storage info");
}
};
}
export default StorageController;
-50
View File
@@ -1,50 +0,0 @@
import disk from "diskusage";
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?: userAccessType,
encryptedToken?: string
}
class StorageController {
constructor() {
}
getStorageInfo = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
if (!env.root || env.root.length === 0) {
return;
}
const info = await disk.check(env.root!);
res.send(info)
} catch (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();
}
}
}
export default StorageController;
+271
View File
@@ -0,0 +1,271 @@
import env from "../enviroment/env";
import UserService from "../services/user-service/user-service";
import { NextFunction, Request, Response } from "express";
import { UserInterface } from "../models/user-model";
import {
createLoginCookie,
createLogoutCookie,
} from "../cookies/create-cookies";
import NotFoundError from "../utils/NotFoundError";
import InternalServerError from "../utils/InternalServerError";
const UserProvider = new UserService();
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() {}
getUser = async (req: RequestType, res: Response, next: NextFunction) => {
try {
const user = req.user!;
res.send(user);
} catch (e) {
next(e);
}
};
login = async (req: RequestType, res: Response, next: NextFunction) => {
try {
const body = req.body;
const currentUUID = req.headers.uuid as string;
const { user, accessToken, refreshToken } = await UserProvider.login(
body,
currentUUID
);
createLoginCookie(res, accessToken, refreshToken);
res.status(200).send({ user });
} catch (e) {
next(e);
}
};
getToken = async (
req: RequestTypeRefresh,
res: Response,
next: NextFunction
) => {
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) {
next(e);
}
};
logout = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const refreshToken = req.cookies["refresh-token"];
await UserProvider.logout(userID, refreshToken);
createLogoutCookie(res);
res.send();
} catch (e) {
createLogoutCookie(res);
next(e);
}
};
logoutAll = async (req: RequestType, res: Response, next: NextFunction) => {
if (!req.user) return;
try {
const userID = req.user._id;
await UserProvider.logoutAll(userID);
createLogoutCookie(res);
res.send();
} catch (e) {
next(e);
}
};
createUser = async (req: RequestType, res: Response, next: NextFunction) => {
try {
const currentUUID = req.headers.uuid as string;
const { user, accessToken, refreshToken, emailSent } =
await UserProvider.create(req.body, currentUUID);
createLoginCookie(res, accessToken, refreshToken);
res.status(201).send({ user, emailSent });
} catch (e) {
next(e);
}
};
changePassword = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const oldPassword = req.body.oldPassword;
const newPassword = req.body.newPassword;
const oldRefreshToken = req.cookies["refresh-token"];
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) {
next(e);
}
};
getUserDetailed = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const userDetailed = await UserProvider.getUserDetailed(userID);
res.send(userDetailed);
} catch (e) {
next(e);
}
};
verifyEmail = async (req: RequestType, res: Response, next: NextFunction) => {
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) {
next(e);
}
};
resendVerifyEmail = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
await UserProvider.resendVerifyEmail(userID);
res.send();
} catch (e) {
next(e);
}
};
sendPasswordReset = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
try {
const email = req.body.email;
await UserProvider.sendPasswordReset(email);
res.send();
} catch (e) {
next(e);
}
};
resetPassword = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
try {
const verifyToken = req.body.passwordToken;
const newPassword = req.body.password;
await UserProvider.resetPassword(newPassword, verifyToken);
res.send();
} catch (e) {
next(e);
}
};
}
export default UserController;
-356
View File
@@ -1,356 +0,0 @@
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();
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() {
}
getUser = async(req: RequestType, res: Response) => {
try {
const user = req.user!;
res.send(user)
} catch (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();
}
}
login = async(req: RequestType, res: Response) => {
try {
const body = req.body;
const currentUUID = req.headers.uuid as string;
const {user, accessToken, refreshToken} = await UserProvider.login(body, currentUUID);
createLoginCookie(res, accessToken, refreshToken);
res.status(200).send({user});
} catch (e) {
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();
}
}
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();
}
}
logout = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const refreshToken = req.cookies["refresh-token"];
await UserProvider.logout(userID, refreshToken);
createLogoutCookie(res);
res.send();
} catch (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 userID = req.user._id;
await UserProvider.logoutAll(userID);
createLogoutCookie(res);
res.send();
} catch (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();
}
}
createUser = async(req: RequestType, res: Response) => {
if (env.createAcctBlocked) {
return await res.status(401).send()
}
try {
const currentUUID = req.headers.uuid as string;
const {user, accessToken, refreshToken} = await UserProvider.create(req.body, currentUUID);
createLoginCookie(res, accessToken, refreshToken);
res.status(201).send({user})
} catch (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();
}
}
changePassword = async(req: RequestType, res: Response) => {
if (!req.user) {
return;
}
try {
const userID = req.user._id;
const oldPassword = req.body.oldPassword;
const newPassword = req.body.newPassword;
const oldRefreshToken = req.cookies["refresh-token"];
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) {
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();
}
}
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();
}
}
}
export default UserController;
-96
View File
@@ -1,96 +0,0 @@
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;
-156
View File
@@ -1,156 +0,0 @@
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;
+83
View File
@@ -0,0 +1,83 @@
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,
}
);
};
-64
View File
@@ -1,64 +0,0 @@
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
})
}
-16
View File
@@ -1,16 +0,0 @@
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,8 @@
import mongoose from "mongoose";
import env from "../../enviroment/env";
mongoose.connect(env.mongoURL!, {
socketTimeoutMS: 30000000,
});
export default mongoose;
+27
View File
@@ -0,0 +1,27 @@
import mongoose from "mongoose";
import env from "../../enviroment/env";
import fs from "fs";
const DBUrl = env.mongoURL as string;
if (env.useDocumentDB === "true") {
console.log("Using DocumentDB");
if (env.documentDBBundle === "true") {
const fileBuffer = fs.readFileSync("./rds-combined-ca-bundle.pem");
const mongooseCertificateConnect = mongoose as any;
mongooseCertificateConnect.connect(DBUrl, {
useCreateIndex: true,
useUnifiedTopology: true,
sslValidate: true,
sslCA: fileBuffer,
});
} else {
mongoose.connect(DBUrl, {});
}
} else {
mongoose.connect(DBUrl, {});
}
export default mongoose;
+12
View File
@@ -0,0 +1,12 @@
import AWS from "aws-sdk";
import env from "../../enviroment/env";
AWS.config.update({
accessKeyId: env.s3ID,
secretAccessKey: env.s3Key,
});
const s3 = new AWS.S3();
export default s3;
module.exports = s3;
-35
View File
@@ -1,35 +0,0 @@
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;
+376
View File
@@ -0,0 +1,376 @@
import mongoose from "../connections/mongoose";
import { ObjectId } from "mongodb";
import File from "../../models/file-model";
import { UserInterface } from "../../models/user-model";
import { createFileQuery } from "../../utils/createQuery";
import { FileListQueryType } from "../../types/file-types";
import sortBySwitch from "../../utils/sortBySwitch";
class DbUtil {
constructor() {}
// READ
getPublicFile = async (fileID: string) => {
const file = await File.findOne({ _id: new ObjectId(fileID) });
return file;
};
getPublicInfo = async (fileID: string, tempToken: string) => {
const file = await File.findOne({
_id: new ObjectId(fileID),
"metadata.link": tempToken,
});
return file;
};
getFileInfo = async (fileID: string, userID: string) => {
const file = await File.findOne({
"metadata.owner": userID,
_id: new ObjectId(fileID),
});
return file;
};
getQuickList = async (userID: string, limit: number) => {
let query: any = {
"metadata.owner": userID,
"metadata.trashed": null,
"metadata.processingFile": null,
};
const fileList = await File.find(query)
.sort({ uploadDate: -1 })
.limit(limit);
return fileList;
};
getList = async (
queryData: FileListQueryType,
sortBy: string,
limit: number
) => {
const formattedSortBy = sortBySwitch(sortBy);
const queryObj = createFileQuery(queryData);
if (sortBy.includes("alp_")) {
const fileList = await File.find(queryObj)
.collation({ locale: "en", strength: 2 })
.sort(formattedSortBy)
.limit(limit);
return fileList;
} else {
const fileList = await File.find(queryObj)
.sort(formattedSortBy)
.limit(limit);
return fileList;
}
};
getFileSearchList = async (
userID: string,
searchQuery: RegExp,
trashMode: boolean,
mediaMode: boolean
) => {
let query: any = {
"metadata.owner": userID,
filename: searchQuery,
"metadata.trashed": trashMode ? true : null,
"metadata.processingFile": null,
};
if (mediaMode) query = { ...query, "metadata.hasThumbnail": true };
const fileList = await File.find(query).limit(10);
return fileList;
};
getFileListByIncludedParent = async (
userID: string | mongoose.Types.ObjectId,
parentListString: string
) => {
const fileList = await File.find({
"metadata.owner": userID,
"metadata.parentList": { $regex: `.*${parentListString}.*` },
});
return fileList;
};
getFileListByOwner = async (userID: string) => {
const fileList = await File.find({ "metadata.owner": userID });
return fileList;
};
getFileListByParent = async (userID: string, parent: string) => {
const fileList = await File.find({
owner: userID,
"metadata.parent": parent,
});
return fileList;
};
// UPDATE
updateFileUploadedFile = async (
fileID: string,
userID: string,
parent: string,
parentList: string
) => {
const file = await File.findOneAndUpdate(
{ _id: new ObjectId(fileID), "metadata.owner": userID },
{
$set: {
"metadata.parent": parent,
"metadata.parentList": parentList,
},
$unset: { "metadata.processingFile": null },
},
{ new: true }
);
return file;
};
updateFolderUploadedFile = async (
fileID: string,
userID: string,
parent: string,
parentList: string
) => {
const file = await File.findOneAndUpdate(
{ _id: new ObjectId(fileID), "metadata.owner": userID },
{
$set: {
"metadata.parent": parent,
"metadata.parentList": parentList,
},
$unset: { "metadata.processingFile": null },
},
{ new: true }
);
return file;
};
setThumbnail = async (fileID: string, thumbnailID: string) => {
const file = await File.findOneAndUpdate(
{ _id: new ObjectId(fileID), "metadata.hasThumbnail": false },
{
$set: {
"metadata.hasThumbnail": true,
"metadata.thumbnailID": thumbnailID,
},
}
);
return file;
};
removeOneTimePublicLink = async (
fileID: string | mongoose.Types.ObjectId
) => {
const file = await File.findOneAndUpdate(
{ _id: new ObjectId(fileID) },
{
$unset: { "metadata.linkType": "", "metadata.link": "" },
}
);
return file;
};
removeLink = async (fileID: string, userID: string) => {
const file = await File.findOneAndUpdate(
{ _id: new ObjectId(fileID), "metadata.owner": userID },
{ $unset: { "metadata.linkType": "", "metadata.link": "" } },
{ new: true }
);
return file;
};
makePublic = async (fileID: string, userID: string, token: string) => {
const file = await File.findOne({
_id: new ObjectId(fileID),
"metadata.owner": userID,
});
if (!file) return null;
file.metadata.linkType = "public";
file.metadata.link = token;
await file.save();
return file;
};
makeOneTimePublic = async (fileID: string, userID: string, token: string) => {
const file = await File.findOne({
_id: new ObjectId(fileID),
"metadata.owner": userID,
});
if (!file) return null;
file.metadata.linkType = "one";
file.metadata.link = token;
await file.save();
return file;
};
trashFile = async (
fileID: string,
parent: string,
parentList: string,
userID: string
) => {
const file = await File.findOne({
_id: new ObjectId(fileID),
"metadata.owner": userID,
});
if (!file) return null;
file.metadata.trashed = true;
file.metadata.parent = parent;
file.metadata.parentList = parentList;
await file.save();
return file;
};
restoreFile = async (fileID: string, userID: string) => {
const file = await File.findOne({
_id: new ObjectId(fileID),
"metadata.owner": userID,
});
if (!file) return null;
file.metadata.trashed = null;
await file.save();
return file;
};
removeTempToken = async (user: UserInterface, tempToken: string) => {
user.tempTokens = user.tempTokens.filter((filterToken) => {
return filterToken.token !== tempToken;
});
return user;
};
trashFilesByParent = async (parentList: string, userID: string) => {
const result = await File.updateMany(
{
"metadata.owner": userID,
"metadata.parentList": { $regex: `.*${parentList}.*` }, // REGEX
},
{
$set: {
"metadata.trashed": true,
},
}
);
return result;
};
restoreFilesByParent = async (parentList: string, userID: string) => {
const result = await File.updateMany(
{
"metadata.owner": userID,
"metadata.parentList": { $regex: `.*${parentList}.*` }, // REGEX
},
{
$set: {
"metadata.trashed": null,
},
}
);
return result;
};
renameFile = async (fileID: string, userID: string, title: string) => {
const file = await File.findOne({
_id: new ObjectId(fileID),
"metadata.owner": userID,
});
if (!file) return null;
file.filename = title;
await file.save();
return file;
};
moveFile = async (
fileID: string | mongoose.Types.ObjectId,
userID: string,
parent: string,
parentList: string
) => {
const file = await File.findOne({
_id: new ObjectId(fileID),
"metadata.owner": userID,
});
if (!file) return null;
file.metadata.parent = parent;
file.metadata.parentList = parentList;
await file.save();
return file;
};
moveMultipleFiles = async (
userID: string | mongoose.Types.ObjectId,
currentParent: string,
newParent: string,
newParentList: string
) => {
await File.updateMany(
{ "metadata.owner": userID, "metadata.parent": currentParent },
{
$set: {
"metadata.parent": newParent,
"metadata.parentList": newParentList,
},
},
{ new: true }
);
};
// DELETE
deleteFile = async (fileID: string, userID: string) => {
const result = await File.deleteOne({
_id: new ObjectId(fileID),
"metadata.owner": userID,
});
return result;
};
}
export default DbUtil;
module.exports = DbUtil;
+251
View File
@@ -0,0 +1,251 @@
import Folder, { FolderInterface } from "../../models/folder-model";
import { ObjectId } from "mongodb";
import { FolderListQueryType } from "../../types/folder-types";
import { createFolderQuery } from "../../utils/createQuery";
import sortBySwitch from "../../utils/sortBySwitchFolder";
class DbUtil {
constructor() {}
// READ
getFolderSearchList = async (
userID: string,
searchQuery: RegExp,
trashMode: boolean
) => {
let query: any = {
owner: userID,
name: searchQuery,
trashed: trashMode ? true : null,
};
const folderList = await Folder.find(query).limit(10);
return folderList;
};
getFolderInfo = async (folderID: string, userID: string) => {
const folder = await Folder.findOne({
owner: userID,
_id: new ObjectId(folderID),
});
return folder;
};
getFolderList = async (queryData: FolderListQueryType, sortBy: string) => {
const query = createFolderQuery(queryData);
const sortByQuery = sortBySwitch(sortBy);
const folderList = await Folder.find(query).sort(sortByQuery);
return folderList;
};
getMoveFolderList = async (
userID: string,
parent = "/",
search?: string,
folderIDs?: string[]
) => {
let query: any = {
owner: userID,
};
// const idQuery = [];
// if (currentParent && currentParent !== "/") {
// idQuery.push(currentParent);
// }
// if (folderID) {
// query.parentList = { $ne: folderID };
// idQuery.push(folderID);
// }
if (folderIDs && folderIDs.length > 0) {
query._id = { $nin: folderIDs };
query.parentList = { $nin: folderIDs };
}
// query._id = { $nin: idQuery };
if (!search || search === "") {
query.parent = parent;
}
if (search && search !== "") {
query.name = new RegExp(search, "i");
}
query.trashed = null;
const result = await Folder.find(query).sort({ createdAt: -1 });
return result;
};
getFolderListByIncludedParent = async (userID: string, parent: string) => {
const folderList = await Folder.find({
owner: userID,
parentList: {
$in: parent,
},
trashed: null,
});
return folderList;
};
findAllFoldersByParent = async (parentID: string, userID: string) => {
const folderList = await Folder.find({
parentList: parentID,
owner: userID,
});
return folderList;
};
// UPDATE
moveFolder = async (
folderID: string,
userID: string,
parent: string,
parentList: string[]
) => {
const folder = await Folder.findOne({
_id: new ObjectId(folderID),
owner: userID,
});
if (!folder) return null;
folder.parent = parent;
folder.parentList = parentList;
await folder.save();
return folder;
};
renameFolder = async (folderID: string, userID: string, title: string) => {
const folder = await Folder.findOne({
_id: new ObjectId(folderID),
owner: userID,
});
if (!folder) return null;
folder.name = title;
await folder.save();
return folder;
};
trashFoldersByParent = async (parentList: string[], userID: string) => {
const result = await Folder.updateMany(
{
owner: userID,
parentList: { $all: parentList },
},
{
$set: {
trashed: true,
},
}
);
return result;
};
restoreFolder = async (folderID: string, userID: string) => {
const folder = await Folder.findOne({
_id: new ObjectId(folderID),
owner: userID,
});
if (!folder) return null;
folder.trashed = null;
await folder.save();
return folder;
};
restoreFoldersByParent = async (parentList: string[], userID: string) => {
const result = await Folder.updateMany(
{
owner: userID,
parentList: { $all: parentList },
},
{
$set: {
trashed: null,
},
}
);
return result;
};
trashFolder = async (folderID: string, userID: string) => {
const folder = await Folder.findOne({
_id: new ObjectId(folderID),
owner: userID,
});
if (!folder) return null;
folder.trashed = true;
await folder.save();
return folder;
};
// CREATE
createFolder = async (folderData: {
name: string;
parent: string;
parentList: string[];
owner: string;
}) => {
const folder = new Folder(folderData);
await folder.save();
return folder;
};
// DELETE
deleteFolder = async (folderID: string, userID: string) => {
const result = await Folder.deleteOne({
_id: new ObjectId(folderID),
owner: userID,
});
return result;
};
deleteFoldersByParentList = async (
parentList: (string | ObjectId)[],
userID: string
) => {
const result = await Folder.deleteMany({
owner: userID,
parentList: { $all: parentList },
});
return result;
};
deleteFoldersByOwner = async (userID: string) => {
const result = await Folder.deleteMany({ owner: userID });
return result;
};
}
export default DbUtil;
+28
View File
@@ -0,0 +1,28 @@
import Thumbnail from "../../models/thumbnail-model";
import { ObjectId } from "mongodb";
class ThumbnailDB {
constructor() {}
// READ
getThumbnailInfo = async (userID: string, thumbnailID: string) => {
const thumbnail = await Thumbnail.findOne({
_id: new ObjectId(thumbnailID),
owner: userID,
});
return thumbnail;
};
// DELETE
removeThumbnail = async (userID: string, thumbnailID: ObjectId) => {
const result = await Thumbnail.deleteOne({
_id: thumbnailID,
owner: userID,
});
return result;
};
}
export default ThumbnailDB;
+15
View File
@@ -0,0 +1,15 @@
import { ObjectId } from "mongodb";
import User from "../../models/user-model";
// READ
class UserDB {
constructor() {}
getUserInfo = async (userID: string) => {
const user = await User.findOne({ _id: new ObjectId(userID) });
return user;
};
}
export default UserDB;
-43
View File
@@ -1,43 +0,0 @@
import mongoose from "mongoose";
import env from "../enviroment/env";
import fs from "fs";
const DBUrl = env.mongoURL as string;
if (env.useDocumentDB === "true") {
console.log("Using DocumentDB");
if (env.documentDBBundle === "true") {
const fileBuffer = fs.readFileSync('./rds-combined-ca-bundle.pem');
const mongooseCertificateConnect = mongoose as any;
mongooseCertificateConnect.connect(DBUrl, {
useCreateIndex: true,
useUnifiedTopology: true,
sslValidate: true,
sslCA: fileBuffer
})
} else {
mongoose.connect(DBUrl, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
sslValidate: true,
})
}
} else {
mongoose.connect(DBUrl, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
})
}
export default mongoose;
-12
View File
@@ -1,12 +0,0 @@
import mongoose from "mongoose";
import env from "../enviroment/env";
mongoose.connect(env.mongoURL!, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
socketTimeoutMS: 30000000,
keepAlive: true,
})
export default mongoose;
-12
View File
@@ -1,12 +0,0 @@
import AWS from "aws-sdk";
import env from "../enviroment/env";
AWS.config.update({
accessKeyId: env.s3ID,
secretAccessKey: env.s3Key
});
const s3 = new AWS.S3();
export default s3;
module.exports = s3;
-170
View File
@@ -1,170 +0,0 @@
import mongoose from "../../mongoose";
import {ObjectID} from "mongodb";
import {FileInterface} from "../../../models/file";
import {UserInterface} from "../../../models/user";
import { QueryInterface } from "../../../utils/createQuery";
const conn = mongoose.connection;
class DbUtil {
constructor() {
}
getPublicFile = async(fileID: string) => {
let file = await conn.db.collection("fs.files")
.findOne({"_id": new ObjectID(fileID)}) as FileInterface;
return file;
}
removeOneTimePublicLink = async(fileID: string) => {
const file = await conn.db.collection("fs.files")
.findOneAndUpdate({"_id": new ObjectID(fileID)}, {
"$unset": {"metadata.linkType": "", "metadata.link": ""}}) as FileInterface;
return file;
}
removeLink = async(fileID: string, userID: string) => {
const file = await conn.db.collection("fs.files")
.findOneAndUpdate({"_id": new ObjectID(fileID),
"metadata.owner": new ObjectID(userID)},
{"$unset": {"metadata.linkType": "", "metadata.link": ""}}) as FileInterface;
return file;
}
makePublic = async(fileID: string, userID: string, token: string) => {
const file = await conn.db.collection("fs.files")
.findOneAndUpdate({"_id": new ObjectID(fileID),
"metadata.owner": new ObjectID(userID)},
{"$set": {"metadata.linkType": "public", "metadata.link": token}}) as FileInterface
return file;
}
getPublicInfo = async(fileID: string, tempToken: string) => {
const file = await conn.db.collection("fs.files")
.findOne({"_id": new ObjectID(fileID), "metadata.link": tempToken}) as FileInterface;
return file;
}
makeOneTimePublic = async(fileID: string, userID: string, token: string) => {
const file = await conn.db.collection("fs.files")
.findOneAndUpdate({"_id": new ObjectID(fileID),
"metadata.owner": new ObjectID(userID)},
{"$set": {"metadata.linkType": "one", "metadata.link": token}}) as FileInterface;
return file;
}
getFileInfo = async(fileID: string, userID: string) => {
const file = await conn.db.collection("fs.files")
.findOne({"metadata.owner": new ObjectID(userID), "_id": new ObjectID(fileID)}) as FileInterface;
return file;
}
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(query)
.sort({uploadDate: -1})
.limit(10)
.toArray() as FileInterface[];
return fileList;
}
getList = async(queryObj: QueryInterface, sortBy: string, limit: number) => {
const fileList = await conn.db.collection("fs.files")
.find(queryObj)
.sort(sortBy)
.limit(limit)
.toArray() as FileInterface[];
return fileList;
}
removeTempToken = async(user: UserInterface, tempToken: string) => {
user.tempTokens = user.tempTokens.filter((filterToken) => {
return filterToken.token !== tempToken;
});
return user;
}
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(query)
.limit(10)
.toArray() as FileInterface[];
return fileList;
}
renameFile = async(fileID: string, userID: string, title: string) => {
const file = await conn.db.collection("fs.files")
.findOneAndUpdate({"_id": new ObjectID(fileID),
"metadata.owner": new ObjectID(userID)}, {"$set": {"filename": title}}) as FileInterface;
return file;
}
moveFile = async(fileID: string, userID: string, parent: string, parentList: string) => {
const file = await conn.db.collection("fs.files")
.findOneAndUpdate({"_id": new ObjectID(fileID),
"metadata.owner": new ObjectID(userID)}, {"$set": {"metadata.parent": parent, "metadata.parentList": parentList}})
return file;
}
getFileListByParent = async(userID: string, parentListString: string) => {
const fileList = await conn.db.collection("fs.files")
.find({"metadata.owner": new ObjectID(userID),
"metadata.parentList": {$regex : `.*${parentListString}.*`}}).toArray() as FileInterface[];
return fileList;
}
getFileListByOwner = async(userID: string) => {
const fileList = await conn.db.collection("fs.files")
.find({"metadata.owner": new ObjectID(userID)}).toArray() as FileInterface[];
return fileList;
}
removeChunksByID = async(fileID: string) => {
await conn.db.collection("fs.chunks").deleteMany({files_id: fileID});
}
}
export default DbUtil;
module.exports = DbUtil;
-113
View File
@@ -1,113 +0,0 @@
import Folder, { FolderInterface } from "../../../models/folder";
import {ObjectID} from "mongodb";
class DbUtil {
constructor() {
}
getFolderSearchList = async(userID: string, searchQuery: RegExp) => {
let query:any = {"owner": userID, "name": searchQuery};
const folderList = await Folder.find(query).limit(10) as FolderInterface[];
return folderList;
}
getFolderInfo = async(folderID: string, userID: string) => {
const folder = await Folder.findOne({"owner": userID, "_id": new ObjectID(folderID)}) as FolderInterface;
return folder;
}
getFolderListByParent = async(userID: string, parent: string, sortBy: string, s3Enabled: boolean, type: string, storageType: string, itemType: string) => {
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, type: string, parent: string, storageType: string, folderSearch: boolean, itemType: string, s3Enabled: boolean) => {
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;
}
moveFolder = async(folderID: string, userID: string, parent: string, parentList: string[]) => {
const folder = await Folder.findOneAndUpdate({"_id": new ObjectID(folderID),
"owner": userID}, {"$set": {"parent": parent, "parentList": parentList}}) as FolderInterface;
return folder;
}
renameFolder = async(folderID: string, userID: string, title: string) => {
const folder = await Folder.findOneAndUpdate({"_id": new ObjectID(folderID),
"owner": userID}, {"$set": {"name": title}}) as FolderInterface;
return folder;
}
findAllFoldersByParent = async(parentID: string, userID: string) => {
const folderList = await Folder.find({"parentList": parentID, "owner": userID}) as FolderInterface[];
return folderList;
}
}
export default DbUtil;
-163
View File
@@ -1,163 +0,0 @@
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;
-100
View File
@@ -1,100 +0,0 @@
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;
+66 -44
View File
@@ -1,47 +1,69 @@
export default {
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
}
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,
secureCookies: process.env.SECURE_COOKIES,
tempDirectory: process.env.TEMP_DIRECTORY,
emailVerification: process.env.EMAIL_VERIFICATION,
emailDomain: process.env.EMAIL_DOMAIN,
emailAPIKey: process.env.EMAIL_API_KEY,
emailHost: process.env.EMAIL_HOST,
emailPort: process.env.EMAIL_PORT,
emailAddress: process.env.EMAIL_ADDRESS,
videoThumbnailsEnabled: process.env.VIDEO_THUMBNAILS_ENABLED === "true",
tempVideoThumbnailLimit: process.env.TEMP_VIDEO_THUMBNAIL_LIMIT
? +process.env.TEMP_VIDEO_THUMBNAIL_LIMIT
: 0,
docker: process.env.DOCKER === "true",
};
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
}
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,
secureCookies: process.env.SECURE_COOKIES,
tempDirectory: process.env.TEMP_DIRECTORY,
emailVerification: process.env.EMAIL_VERIFICATION,
emailDomain: process.env.EMAIL_DOMAIN,
emailAPIKey: process.env.EMAIL_API_KEY,
emailHost: process.env.EMAIL_HOST,
emailPort: process.env.EMAIL_PORT,
emailAddress: process.env.EMAIL_ADDRESS,
videoThumbnailsEnabled: process.env.VIDEO_THUMBNAILS_ENABLED === "true",
tempVideoThumbnailLimit: process.env.TEMP_VIDEO_THUMBNAIL_LIMIT
? +process.env.TEMP_VIDEO_THUMBNAIL_LIMIT
: 0,
docker: process.env.DOCKER === "true",
};
+18
View File
@@ -0,0 +1,18 @@
import path from "path";
const getEnvVariables = () => {
const configPath = path.join(__dirname, "..", "..", "backend", "config");
const processType = process.env.NODE_ENV;
if (processType === "production" || processType === undefined) {
require("dotenv").config({ path: configPath + "/.env.production" });
} else if (processType === "development") {
require("dotenv").config({ path: configPath + "/.env.development" });
} else if (processType === "test") {
require("dotenv").config({ path: configPath + "/.env.test" });
}
};
export default getEnvVariables;
module.exports = getEnvVariables;
-24
View File
@@ -1,24 +0,0 @@
import path from "path";
const getEnvVariables = () => {
const configPath = path.join(__dirname, "..", "..", "config");
const processType = process.env.NODE_ENV;
if (processType === 'production' || processType === undefined) {
require('dotenv').config({ path: configPath + "/prod.env"})
} else if (processType === 'development') {
require('dotenv').config({ path: configPath + "/dev.env"})
} else if (processType === 'test') {
require('dotenv').config({ path: configPath + "/test.env"})
}
}
export default getEnvVariables;
module.exports = getEnvVariables
+214
View File
@@ -0,0 +1,214 @@
import { Router } from "express";
import auth from "../middleware/auth";
import FileController from "../controllers/file-controller";
import authFullUser from "../middleware/authFullUser";
import authStreamVideo from "../middleware/authStreamVideo";
import {
deleteFileValidationRules,
deleteMultiValidationRules,
downloadFileValidationRules,
getFileInfoValidationRules,
getListValidationRules,
getPublicDownloadValidationRules,
getQuickListValidationRules,
getSuggestedListValidationRules,
getThumbnailValidationRules,
makePrivateValidationRules,
makePublicValidationRules,
moveFileValidationRules,
moveMultiValidationRules,
removeVideoStreamTokenValidationRules,
renameFileValidationRules,
restoreFileValidationRules,
restoreMultiValidationRules,
streamVideoValidationRules,
trashFileValidationRules,
trashMultiValidationRules,
} from "../middleware/files/files-middleware";
const fileController = new FileController();
const router = Router();
// GET
router.get(
"/file-service/thumbnail/:id",
authFullUser,
getThumbnailValidationRules,
fileController.getThumbnail
);
router.get(
"/file-service/full-thumbnail/:id",
authFullUser,
getThumbnailValidationRules,
fileController.getFullThumbnail
);
router.get(
"/file-service/public/download/:id/:tempToken",
getPublicDownloadValidationRules,
fileController.getPublicDownload
);
router.get(
"/file-service/public/info/:id/:tempToken",
getPublicDownloadValidationRules,
fileController.getPublicInfo
);
router.get(
"/file-service/info/:id",
auth,
getFileInfoValidationRules,
fileController.getFileInfo
);
router.get(
"/file-service/quick-list",
auth,
getQuickListValidationRules,
fileController.getQuickList
);
router.get(
"/file-service/list",
auth,
getListValidationRules,
fileController.getList
);
router.get(
"/file-service/download/access-token-stream-video",
authFullUser,
fileController.getAccessTokenStreamVideo
);
router.get(
"/file-service/stream-video/:id",
authStreamVideo,
streamVideoValidationRules,
fileController.streamVideo
);
router.delete(
"/file-service/remove-stream-video-token",
authStreamVideo,
fileController.removeStreamVideoAccessToken
);
router.get(
"/file-service/download/:id",
authFullUser,
downloadFileValidationRules,
fileController.downloadFile
);
router.get(
"/file-service/suggested-list",
auth,
getSuggestedListValidationRules,
fileController.getSuggestedList
);
// PATCH
router.patch(
"/file-service/make-public/:id",
authFullUser,
makePublicValidationRules,
fileController.makePublic
);
router.patch(
"/file-service/make-one/:id",
auth,
makePublicValidationRules,
fileController.makeOneTimePublic
);
router.patch(
"/file-service/rename",
auth,
renameFileValidationRules,
fileController.renameFile
);
router.patch(
"/file-service/move",
auth,
moveFileValidationRules,
fileController.moveFile
);
router.patch(
"/file-service/move-multi",
auth,
moveMultiValidationRules,
fileController.moveMultiFile
);
router.patch(
"/file-service/trash",
auth,
trashFileValidationRules,
fileController.trashFile
);
router.patch(
"/file-service/trash-multi",
auth,
trashMultiValidationRules,
fileController.trashMulti
);
router.patch(
"/file-service/restore",
auth,
restoreFileValidationRules,
fileController.restoreFile
);
router.patch(
"/file-service/restore-multi",
auth,
restoreMultiValidationRules,
fileController.restoreMulti
);
router.patch(
"/file-service/remove-link/:id",
auth,
makePrivateValidationRules,
fileController.removeLink
);
// DELETE
router.delete(
"/file-service/remove/token-video/:id",
auth,
removeVideoStreamTokenValidationRules,
fileController.removeTempToken
);
router.delete(
"/file-service/remove",
auth,
deleteFileValidationRules,
fileController.deleteFile
);
router.delete(
"/file-service/remove-multi",
auth,
deleteMultiValidationRules,
fileController.deleteMulti
);
// POST
router.post("/file-service/upload", authFullUser, fileController.uploadFile);
export default router;
-86
View File
@@ -1,86 +0,0 @@
import {Router} from "express";
import auth from "../middleware/auth";
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", authFullUser, fileController.uploadFile);
router.get("/file-service/thumbnail/:id", authFullUser, fileController.getThumbnail);
router.get("/file-service/full-thumbnail/:id", authFullUser, fileController.getFullThumbnail);
router.get("/file-service/public/download/:id/:tempToken", fileController.getPublicDownload);
router.get("/file-service/public/info/:id/:tempToken", fileController.getPublicInfo);
router.get("/file-service/info/:id", auth, fileController.getFileInfo);
router.get("/file-service/quick-list", auth, fileController.getQuickList);
router.get("/file-service/list", auth, fileController.getList);
router.get("/file-service/download/access-token-stream-video", authFullUser, fileController.getAccessTokenStreamVideo)
router.get("/file-service/stream-video/:id", authStreamVideo, fileController.streamVideo);
router.delete("/file-service/remove-stream-video-token", authStreamVideo, fileController.removeStreamVideoAccessToken);
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", authFullUser, fileController.makePublic);
router.patch("/file-service/make-one/:id", auth, fileController.makeOneTimePublic);
router.patch("/file-service/rename", auth, fileController.renameFile);
router.patch("/file-service/move", auth, fileController.moveFile);
router.delete("/file-service/remove-link/:id", auth, fileController.removeLink);
router.delete("/file-service/remove/token-video/:id", auth, fileController.removeTempToken);
router.delete("/file-service/remove", auth, fileController.deleteFile);
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);
+107
View File
@@ -0,0 +1,107 @@
import { Router } from "express";
import auth from "../middleware/auth";
import FolderController from "../controllers/folder-controller";
import {
createFolderValidationRules,
deleteFolderValidationRules,
downloadZipValidationRules,
getFolderInfoValidationRules,
getFolderListValidationRules,
moveFolderListValidationRules,
moveFolderValidationRules,
renameFolderValidationRules,
restoreFolderValidationRules,
trashFolderValidationRules,
} from "../middleware/folders/folder-middleware";
import authFullUser from "../middleware/authFullUser";
const folderController = new FolderController();
const router = Router();
// GET
router.get(
"/folder-service/info/:id",
auth,
getFolderInfoValidationRules,
folderController.getInfo
);
router.get(
"/folder-service/list",
auth,
getFolderListValidationRules,
folderController.getFolderList
);
router.get(
"/folder-service/move-folder-list",
auth,
moveFolderListValidationRules,
folderController.getMoveFolderList
);
router.get(
"/folder-service/download-zip",
auth,
downloadZipValidationRules,
folderController.downloadZip
);
// PATCH
router.patch(
"/folder-service/rename",
auth,
renameFolderValidationRules,
folderController.renameFolder
);
router.patch(
"/folder-service/move",
auth,
moveFolderValidationRules,
folderController.moveFolder
);
router.patch(
"/folder-service/trash",
auth,
trashFolderValidationRules,
folderController.trashFolder
);
router.patch(
"/folder-service/restore",
auth,
restoreFolderValidationRules,
folderController.restoreFolder
);
// DELETE
router.delete(
"/folder-service/remove",
auth,
deleteFolderValidationRules,
folderController.deleteFolder
);
router.delete("/folder-service/remove-all", auth, folderController.deleteAll);
// POST
router.post(
"/folder-service/create",
auth,
createFolderValidationRules,
folderController.createFolder
);
router.post(
"/folder-service/upload",
authFullUser,
folderController.uploadFolder
);
export default router;
-51
View File
@@ -1,51 +0,0 @@
import {Router} from "express";
import auth from "../middleware/auth";
import env from "../enviroment/env";
import MongoService from "../services/ChunkService/MongoService";
import FileSystemService from "../services/ChunkService/FileSystemService";
import S3Service from "../services/ChunkService/S3Service";
import FolderController from "../controllers/folder";
let folderController: FolderController;
if (env.dbType === "mongo") {
const mongoService = new MongoService();
folderController = new FolderController(mongoService);
} else if (env.dbType === "fs") {
const fileSystemService = new FileSystemService();
folderController = new FolderController(fileSystemService);
} else {
const s3Service = new S3Service();
folderController = new FolderController(s3Service);
}
const router = Router();
router.post("/folder-service/upload", auth, folderController.uploadFolder);
router.delete("/folder-service/remove", auth, folderController.deleteFolder);
router.delete("/folder-service/remove-all", auth, folderController.deleteAll);
router.get("/folder-service/info/:id", auth, folderController.getInfo);
router.get("/folder-service/subfolder-list", auth, folderController.getSubfolderList);
router.get("/folder-service/list", auth, folderController.getFolderList);
router.patch("/folder-service/rename", auth, folderController.renameFolder);
router.patch("/folder-service/move", auth, folderController.moveFolder);
router.get("/folder-service/subfolder-list-full", auth, folderController.getSubfolderFullList);
// Personal Folder
router.delete("/folder-service-personal/remove", auth, folderController.deletePersonalFolder);
export default router;
-42
View File
@@ -1,42 +0,0 @@
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;
-27
View File
@@ -1,27 +0,0 @@
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;
-26
View File
@@ -1,26 +0,0 @@
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;
-13
View File
@@ -1,13 +0,0 @@
import {Router} from "express";
import auth from "../middleware/auth";
import StorageController from "../controllers/storage";
const storageController = new StorageController();
const router = Router();
// No longer needed left for reference
// router.get("/storage-service/info", auth, storageController.getStorageInfo);
export default router;
+66
View File
@@ -0,0 +1,66 @@
import { Router } from "express";
import auth from "../middleware/auth";
import UserController from "../controllers/user-controller";
import authRefresh from "../middleware/authRefresh";
import authLogout from "../middleware/authLogout";
import {
changePasswordValidationRules,
createAccountValidationRules,
loginAccountValidationRules,
} from "../middleware/user/user-middleware";
const userController = new UserController();
const router = Router();
// GET
router.get("/user-service/user", auth, userController.getUser);
router.get("/user-service/user-detailed", auth, userController.getUserDetailed);
// POST
router.post(
"/user-service/login",
loginAccountValidationRules,
userController.login
);
router.post("/user-service/logout", authLogout, userController.logout);
router.post("/user-service/logout-all", authLogout, userController.logoutAll);
router.post(
"/user-service/create",
createAccountValidationRules,
userController.createUser
);
router.post("/user-service/get-token", authRefresh, userController.getToken);
// PATCH
router.patch(
"/user-service/change-password",
auth,
changePasswordValidationRules,
userController.changePassword
);
router.patch(
"/user-service/resend-verify-email",
auth,
userController.resendVerifyEmail
);
router.patch("/user-service/verify-email", userController.verifyEmail);
router.patch("/user-service/reset-password", userController.resetPassword);
router.patch(
"/user-service/send-password-reset",
userController.sendPasswordReset
);
export default router;
-40
View File
@@ -1,40 +0,0 @@
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", 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", authLogout, userController.logout);
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;
-15
View File
@@ -1,15 +0,0 @@
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;
-20
View File
@@ -1,20 +0,0 @@
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;
+39
View File
@@ -0,0 +1,39 @@
import env from "../enviroment/env";
import crypto from "crypto";
import getKeyFromTerminal from "../utils/getKeyFromTerminal";
const getKey = async () => {
if (
process.env.KEY ||
process.env.NODE_ENV === "development" ||
process.env.NODE_ENV === "test"
) {
const password = process.env.KEY;
if (!password) {
console.log(`Key is required for ${process.env.NODE_ENV} server`);
throw new Error(`Key is required for ${process.env.NODE_ENV} server`);
}
env.key = crypto.createHash("md5").update(password).digest("hex");
} else if (process.env.NODE_ENV === "production" && !process.env.KEY) {
const terminalPassword = await getKeyFromTerminal();
if (!terminalPassword || !terminalPassword.length) {
console.log(
"Terminal key is required for production server, or create a .env file with KEY"
);
throw new Error(
"Terminal key is required for production server, or create a .env file with KEY"
);
}
const password = crypto
.createHash("md5")
.update(terminalPassword)
.digest("hex");
env.key = password;
}
};
export default getKey;
-32
View File
@@ -1,32 +0,0 @@
import env from "../enviroment/env";
import crypto from "crypto";
import getWebUIKey from "./getWebUIKey";
const getKey = async() => {
if (process.env.KEY) {
// For Docker
const password = process.env.KEY;
env.key = crypto.createHash("md5").update(password).digest("hex");
} else if (process.env.NODE_ENV === "production") {
let password = await getWebUIKey();
password = crypto.createHash("md5").update(password).digest("hex");
env.key = password;
} else {
let password = "1234";
password = crypto.createHash("md5").update(password).digest("hex");
env.key = password;
}
}
export default getKey;
+34 -35
View File
@@ -1,54 +1,53 @@
import jwt from "jsonwebtoken";
import env from "../enviroment/env";
import {Request, Response, NextFunction} from "express";
import { Request, Response, NextFunction } from "express";
interface RequestType extends Request {
user?: userAccessType,
token?: string,
encryptedToken?: string,
user?: userAccessType;
token?: string;
encryptedToken?: string;
}
type jwtType = {
iv: Buffer,
user: userAccessType
}
iv: Buffer;
user: userAccessType;
};
type userAccessType = {
_id: string,
emailVerified: boolean,
email: string,
admin: boolean,
botChecked: boolean,
username: string,
}
_id: string;
emailVerified: boolean;
email: string;
admin: boolean;
botChecked: boolean;
username: string;
};
const auth = async(req: RequestType, res: Response, next: NextFunction) => {
const auth = async (req: RequestType, res: Response, next: NextFunction) => {
try {
const accessToken = req.cookies["access-token"];
try {
if (!accessToken) throw new Error("No Access Token");
const accessToken = req.cookies["access-token"];
const decoded = jwt.verify(accessToken, env.passwordAccess!) as jwtType;
if (!accessToken) throw new Error("No Access Token");
const user = decoded.user;
const decoded = jwt.verify(accessToken, env.passwordAccess!) as jwtType;
if (!user) throw new Error("No User");
const user = decoded.user;
req.user = user;
if (!user) throw new Error("No User");
if (!user.emailVerified && !env.disableEmailVerification) throw new Error("Email Not Verified")
req.user = user;
next();
} catch (e) {
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");
next();
} catch (e: unknown) {
if (
e instanceof Error &&
e.message !== "No Access Token" &&
e.message !== "No User"
) {
console.log("\nAuthorization Middleware Error:", e.message);
}
}
res.status(401).send("Error Authenticating");
}
};
export default auth;
+42 -39
View File
@@ -1,59 +1,62 @@
import jwt from "jsonwebtoken";
import User, {UserInterface} from "../models/user";
import User, { UserInterface } from "../models/user-model";
import env from "../enviroment/env";
import {Request, Response, NextFunction} from "express";
import { Request, Response, NextFunction } from "express";
interface RequestType extends Request {
user?: UserInterface,
token?: string,
encryptedToken?: string,
user?: UserInterface;
token?: string;
encryptedToken?: string;
}
type jwtType = {
iv: Buffer,
user: userAccessType
}
iv: Buffer;
user: userAccessType;
};
type userAccessType = {
_id: string,
emailVerified: boolean,
email: string,
admin: boolean,
botChecked: boolean,
username: string,
}
_id: string;
emailVerified: boolean;
email: string;
admin: boolean;
botChecked: boolean;
username: string;
};
const authFullUser = async(req: RequestType, res: Response, next: NextFunction) => {
const authFullUser = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
try {
const accessToken = req.cookies["access-token"];
try {
if (!accessToken) throw new Error("No Access Token");
const accessToken = req.cookies["access-token"];
const decoded = jwt.verify(accessToken, env.passwordAccess!) as jwtType;
if (!accessToken) throw new Error("No Access Token");
const user = decoded.user;
const decoded = jwt.verify(accessToken, env.passwordAccess!) as jwtType;
if (!user) throw new Error("No User");
const user = decoded.user;
const fullUser = await User.findById(user._id);
if (!user) throw new Error("No User");
if (!user.emailVerified && !env.disableEmailVerification) throw new Error("Email Not Verified")
if (!fullUser) throw new Error("No User");
const fullUser = await User.findById(user._id);
req.user = fullUser;
if (!fullUser) throw new Error("No User");
next();
} catch (e) {
if (
e instanceof Error &&
e.message !== "No Access Token" &&
e.message !== "No User" &&
e.message !== "Email Not Verified"
)
console.log("\nAuthorization Full User Middleware Error:", e.message);
req.user = fullUser;
res.status(401).send("Error Authenticating");
}
};
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;
export default authFullUser;
+35 -34
View File
@@ -1,52 +1,53 @@
import jwt from "jsonwebtoken";
import env from "../enviroment/env";
import {Request, Response, NextFunction} from "express";
import { createLogoutCookie } from "../cookies/createCookies";
import { Request, Response, NextFunction } from "express";
import { createLogoutCookie } from "../cookies/create-cookies";
interface RequestType extends Request {
user?: userAccessType,
token?: string,
encryptedToken?: string,
user?: userAccessType;
token?: string;
encryptedToken?: string;
}
type jwtType = {
iv: Buffer,
user: userAccessType
}
iv: Buffer;
user: userAccessType;
};
type userAccessType = {
_id: string,
emailVerified: boolean,
email: string,
botChecked: boolean,
}
_id: string;
emailVerified: boolean;
email: string;
botChecked: boolean;
};
const auth = async(req: RequestType, res: Response, next: NextFunction) => {
const auth = async (req: RequestType, res: Response, next: NextFunction) => {
try {
const accessToken = req.cookies["access-token"];
try {
if (!accessToken) throw new Error("No Access Token");
const accessToken = req.cookies["access-token"];
const decoded = jwt.verify(accessToken, env.passwordAccess!) as jwtType;
if (!accessToken) throw new Error("No Access Token");
const user = decoded.user;
const decoded = jwt.verify(accessToken, env.passwordAccess!) as jwtType;
if (!user) throw new Error("No User");
const user = decoded.user;
req.user = 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");
next();
} catch (e) {
if (
e instanceof Error &&
e.message !== "No Access Token" &&
e.message !== "No User"
) {
console.log("\nAuthorization Logout Middleware Error:", e.message);
}
}
export default auth;
createLogoutCookie(res);
return res.status(401).send("Error Authenticating");
}
};
export default auth;
@@ -1,57 +0,0 @@
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;
+79 -72
View File
@@ -1,92 +1,99 @@
import jwt from "jsonwebtoken";
import User, {UserInterface} from "../models/user";
import User, { UserInterface } from "../models/user-model";
import env from "../enviroment/env";
import {Request, Response, NextFunction} from "express";
import { ObjectID } from "mongodb";
import { Request, Response, NextFunction } from "express";
import { ObjectId } from "mongodb";
import mongoose from "mongoose";
interface RequestType extends Request {
user?: UserInterface,
token?: string,
encryptedToken?: string,
user?: UserInterface;
token?: string;
encryptedToken?: string;
}
type jwtType = {
iv: Buffer,
_id: string,
time: number
}
iv: Buffer;
_id: string;
time: number;
};
const removeOldTokens = async(userID: string, uuid: string | undefined, oldTime: number) => {
const removeOldTokens = async (
userID: mongoose.Types.ObjectId,
uuid: string | undefined,
oldTime: number
) => {
try {
const minusTime = oldTime - 1000 * 60 * 60;
//const minusTime = oldTime - (1000);
try {
uuid = uuid ? uuid : "unknown";
const minusTime = oldTime - (1000 * 60 * 60);
//const minusTime = oldTime - (1000);
if (uuid === "unknown") return;
uuid = uuid ? uuid : "unknown";
await User.updateOne(
{ _id: userID },
{ $pull: { tokens: { uuid, time: { $lt: minusTime } } } }
);
} catch (e) {
console.log("cannot remove old tokens", e);
}
};
if (uuid === "unknown") return;
const authRefresh = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
try {
const refreshToken = req.cookies["refresh-token"];
const currentUUID = req.headers.uuid as string;
await User.updateOne({_id: userID}, {$pull: {tokens: {uuid, time: {$lt: minusTime}}}})
if (!refreshToken) throw new Error("No Refresh Token");
} catch (e) {
console.log("cannot remove old tokens", e);
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;
}
}
}
const authRefresh = async(req: RequestType, res: Response, next: NextFunction) => {
if (!tokenFound) throw new Error("Refresh Token Not Found");
try {
req.user = user;
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");
next();
} catch (e) {
if (
e instanceof Error &&
e.message !== "No Refresh Token" &&
e.message !== "No User" &&
e.message !== "Refresh Token Not Found"
) {
console.log("\nAuthorization Refresh Middleware Error:", e.message);
}
}
export default authRefresh;
res.status(401).send("Error Refreshing Token");
}
};
export default authRefresh;
+82 -68
View File
@@ -1,89 +1,103 @@
import jwt from "jsonwebtoken";
import User, {UserInterface} from "../models/user";
import User, { UserInterface } from "../models/user-model";
import env from "../enviroment/env";
import {Request, Response, NextFunction} from "express";
import { ObjectID } from "mongodb";
import { Request, Response, NextFunction } from "express";
import { ObjectId } from "mongodb";
import mongoose from "mongoose";
interface RequestType extends Request {
user?: UserInterface,
token?: string,
encryptedToken?: string,
accessTokenStreamVideo?: string
user?: UserInterface;
token?: string;
encryptedToken?: string;
accessTokenStreamVideo?: string;
}
type jwtType = {
iv: Buffer,
_id: string,
time: number
}
iv: Buffer;
_id: string;
time: number;
};
const removeOldTokens = async(userID: string, uuid: string | undefined, oldTime: number) => {
const removeOldTokens = async (
userID: mongoose.Types.ObjectId,
uuid: string | undefined,
oldTime: number
) => {
try {
const minusTime = oldTime - 60 * 1000 * 60 * 24;
try {
uuid = uuid ? uuid : "unknown";
const minusTime = oldTime - (60 * 1000 * 60 * 24);
if (uuid === "unknown") return;
uuid = uuid ? uuid : "unknown";
await User.updateOne(
{ _id: userID },
{ $pull: { tempTokens: { uuid, time: { $lt: minusTime } } } }
);
} catch (e) {
console.log("cannot remove old tokens", e);
}
};
if (uuid === "unknown") return;
const authStreamVideo = async (
req: RequestType,
res: Response,
next: NextFunction
) => {
try {
const accessTokenStreamVideo = req.cookies["video-access-token"];
const currentUUID = req.headers.uuid as string;
await User.updateOne({_id: userID}, {$pull: {tempTokens: {uuid, time: {$lt: minusTime}}}})
if (!accessTokenStreamVideo) throw new Error("No Access Token");
} catch (e) {
console.log("cannot remove old tokens", e);
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");
const authStreamVideo = async(req: RequestType, res: Response, next: NextFunction) => {
req.user = user;
req.accessTokenStreamVideo = encryptedToken;
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");
next();
} catch (e) {
if (
e instanceof Error &&
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;
@@ -0,0 +1,155 @@
import { body, param, query, validationResult } from "express-validator";
import { Request, Response, NextFunction } from "express";
import { middlewareValidationFunction } from "../utils/middleware-utils";
// GET
export const getThumbnailValidationRules = [
param("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const getPublicDownloadValidationRules = [
param("id").isString().withMessage("ID must be a string"),
param("tempToken").isString().withMessage("Temp Token must be a string"),
middlewareValidationFunction,
];
export const getFileInfoValidationRules = [
param("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const getQuickListValidationRules = [
query("limit").optional().isNumeric().withMessage("Limit must be a number"),
middlewareValidationFunction,
];
export const getListValidationRules = [
query("search").optional().isString().withMessage("Search must be a string"),
query("parent").optional().isString().withMessage("Parent must be a string"),
query("startAtDate")
.optional()
.isString()
.withMessage("Start At Date must be a string"),
query("startAtName")
.optional()
.isString()
.withMessage("Start At Name must be a string"),
query("trashMode")
.optional()
.isBoolean()
.withMessage("Trash Mode must be a boolean"),
query("mediaFilter")
.optional()
.isString()
.withMessage("Media Filter must be a string"),
query("mediaMode")
.optional()
.isBoolean()
.withMessage("Media Mode must be a boolean"),
query("sortBy").optional().isString().withMessage("Sort By must be a string"),
middlewareValidationFunction,
];
export const getSuggestedListValidationRules = [
query("search")
.optional()
.isString()
.isLength({ min: 1, max: 255 })
.withMessage("Search must be a string"),
query("trashMode")
.optional()
.isBoolean()
.withMessage("Trash Mode must be a boolean"),
query("mediaMode")
.optional()
.isBoolean()
.withMessage("Media Mode must be a boolean"),
middlewareValidationFunction,
];
export const streamVideoValidationRules = [
param("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const downloadFileValidationRules = [
param("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
// PATCH
export const renameFileValidationRules = [
body("id").isString().withMessage("ID must be a string"),
body("title")
.exists()
.withMessage("Title is required")
.isString()
.withMessage("Title must be a string")
.isLength({ min: 1, max: 256 })
.withMessage(
"Title must be at least 1 character and at most 256 characters"
),
middlewareValidationFunction,
];
export const moveFileValidationRules = [
body("id").isString().withMessage("FileID must be a string"),
body("parentID").isString().optional().withMessage("Parent must be a string"),
middlewareValidationFunction,
];
export const moveMultiValidationRules = [
body("items").isArray().withMessage("Items must be an array"),
body("parentID").isString().optional().withMessage("Parent must be a string"),
middlewareValidationFunction,
];
export const trashFileValidationRules = [
body("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const trashMultiValidationRules = [
body("items").isArray().withMessage("Items must be an array"),
middlewareValidationFunction,
];
export const restoreFileValidationRules = [
body("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const restoreMultiValidationRules = [
body("items").isArray().withMessage("Items must be an array"),
middlewareValidationFunction,
];
export const makePublicValidationRules = [
param("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const makePrivateValidationRules = [
param("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const removeVideoStreamTokenValidationRules = [
param("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
// DELETE
export const deleteFileValidationRules = [
body("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const deleteMultiValidationRules = [
body("items").isArray().withMessage("Items must be an array"),
middlewareValidationFunction,
];
@@ -0,0 +1,98 @@
import { body, param, query, validationResult } from "express-validator";
import { Request, Response, NextFunction } from "express";
import { middlewareValidationFunction } from "../utils/middleware-utils";
// GET
export const moveFolderListValidationRules = [
query("parent").optional().isString().withMessage("Parent must be a string"),
query("search").optional().isString().withMessage("Search must be a string"),
query("folderIDs")
.optional()
.isArray()
.withMessage("FolderIDs must be an array of strings"),
middlewareValidationFunction,
];
export const getFolderInfoValidationRules = [
param("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const getFolderListValidationRules = [
query("search").optional().isString().withMessage("Search must be a string"),
query("parent").optional().isString().withMessage("Parent must be a string"),
query("sortBy").optional().isString().withMessage("Sort By must be a string"),
query("trashMode")
.optional()
.isBoolean()
.withMessage("Trash Mode must be a boolean"),
middlewareValidationFunction,
];
export const downloadZipValidationRules = [
query("folderIDs")
.optional()
.isArray()
.withMessage("FolderIDs must be an array of strings"),
query("fileIDs")
.optional()
.isArray()
.withMessage("FileIDs must be an array of strings"),
middlewareValidationFunction,
];
// PATCH
export const renameFolderValidationRules = [
body("id").isString().withMessage("ID must be a string"),
body("title")
.exists()
.withMessage("Title is required")
.isString()
.withMessage("Title must be a string")
.isLength({ min: 1, max: 256 })
.withMessage(
"Title must be at least 1 character and at most 256 characters"
),
middlewareValidationFunction,
];
export const moveFolderValidationRules = [
body("parentID").isString().withMessage("Parent must be a string"),
body("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const trashFolderValidationRules = [
body("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const restoreFolderValidationRules = [
body("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
// DELETE
export const deleteFolderValidationRules = [
body("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
// POST
export const createFolderValidationRules = [
body("name")
.exists()
.withMessage("Name is required")
.isString()
.withMessage("Name must be a string")
.isLength({ min: 1, max: 256 })
.withMessage(
"Name must be at least 1 character and at most 256 characters"
),
body("parent").optional().isString().withMessage("Parent must be a string"),
middlewareValidationFunction,
];
@@ -0,0 +1,77 @@
import { body, param, query, validationResult } from "express-validator";
import { Request, Response, NextFunction } from "express";
import { middlewareValidationFunction } from "../utils/middleware-utils";
// PATCH
export const changePasswordValidationRules = [
body("oldPassword")
.exists()
.withMessage("Old password is required")
.isString()
.withMessage("Old password must be a string")
.isLength({ min: 6, max: 256 })
.withMessage(
"Old password must be at least 6 characters and at most 256 characters"
),
body("newPassword")
.exists()
.withMessage("New password is required")
.isString()
.withMessage("New password must be a string")
.isLength({ min: 6, max: 256 })
.withMessage(
"New password must be at least 6 characters and at most 256 characters"
),
middlewareValidationFunction,
];
// POST
export const createAccountValidationRules = [
body("email")
.exists()
.withMessage("Email is required")
.isString()
.withMessage("Email must be a string")
.isLength({ min: 3, max: 320 })
.withMessage(
"Email must be at least 3 characters and at most 320 characters"
)
.isEmail()
.withMessage("Email is invalid"),
body("password")
.exists()
.withMessage("Password is required")
.isString()
.withMessage("Password must be a string")
.isLength({ min: 6, max: 256 })
.withMessage(
"Password must be at least 6 characters and at most 256 characters"
),
middlewareValidationFunction,
];
export const loginAccountValidationRules = [
body("email")
.exists()
.withMessage("Email is required")
.isString()
.withMessage("Email must be a string")
.isLength({ min: 3, max: 320 })
.withMessage(
"Email must be at least 3 characters and at most 320 characters"
)
.isEmail()
.withMessage("Email is invalid"),
body("password")
.exists()
.withMessage("Password is required")
.isString()
.withMessage("Password must be a string")
.isLength({ min: 6, max: 256 })
.withMessage(
"Password must be at least 6 characters and at most 256 characters"
),
middlewareValidationFunction,
];
@@ -0,0 +1,43 @@
import e, { NextFunction } from "express";
import { validationResult } from "express-validator";
import { Request, Response } from "express";
import NotAuthorizedError from "../../utils/NotAuthorizedError";
import NotFoundError from "../../utils/NotFoundError";
import InternalServerError from "../../utils/InternalServerError";
import ForbiddenError from "../../utils/ForbiddenError";
import NotValidDataError from "../../utils/NotValidDataError";
import ConflictError from "../../utils/ConflictError";
export const middlewareValidationFunction = (
req: Request,
res: Response,
next: NextFunction
) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
};
export const middlewareErrorHandler = (
error: Error,
_req: Request,
res: Response,
_next: NextFunction
) => {
console.log("Express route error: ", error);
if (
error instanceof NotAuthorizedError ||
error instanceof ForbiddenError ||
error instanceof NotFoundError ||
error instanceof InternalServerError ||
error instanceof NotValidDataError ||
error instanceof ConflictError
) {
return res.status(error.code).send(error.message);
}
res.status(500).send("Server error");
};
+112
View File
@@ -0,0 +1,112 @@
import mongoose, { Document } from "mongoose";
import { Binary, ObjectId } from "mongodb";
const fileSchema = new mongoose.Schema({
length: {
type: Number,
required: true,
},
chunkSize: {
type: Number,
},
uploadDate: {
type: Date,
required: true,
},
filename: {
type: String,
required: true,
validate(value: any) {
if (!value || value.length === 0 || value.length >= 256) {
throw new Error(
"Filename is required and length must be greater than 0 and 256 characters max"
);
}
},
},
metadata: {
type: {
owner: {
type: String,
required: true,
},
parent: {
type: String,
required: true,
},
parentList: {
type: String,
required: true,
},
hasThumbnail: {
type: Boolean,
required: true,
},
isVideo: {
type: Boolean,
required: true,
},
thumbnailID: String,
size: {
type: Number,
required: true,
},
IV: {
type: Buffer,
required: true,
},
linkType: String,
link: String,
filePath: String,
s3ID: String,
personalFile: Boolean,
trashed: Boolean,
processingFile: Boolean,
},
required: true,
},
});
export interface FileMetadateInterface {
owner: string;
parent: string;
parentList: string;
hasThumbnail: boolean;
isVideo: boolean;
thumbnailID?: string;
size: number;
IV: Buffer;
linkType?: "one" | "public";
link?: string;
filePath?: string;
s3ID?: string;
personalFile?: boolean;
trashed?: boolean | null;
processingFile?: boolean;
}
export interface FileInterface
extends mongoose.Document<mongoose.Types.ObjectId> {
length: number;
chunkSize: number;
uploadDate: string;
filename: string;
lastErrorObject: { updatedExisting: any };
metadata: FileMetadateInterface;
}
fileSchema.index(
{ "metadata.owner": 1, "metadata.parent": 1, filename: 1 },
{ collation: { locale: "en", strength: 2 }, background: true }
);
fileSchema.index(
{ "metadata.owner": 1, "metadata.parent": 1, uploadDate: 1 },
{ background: true }
);
fileSchema.index({ "metadata.trashed": 1 }, { background: true });
fileSchema.index({ "metadata.hasThumbnail": 1 }, { background: true });
const File = mongoose.model<FileInterface>("fs.files", fileSchema);
export default File;
module.exports = File;
-90
View File
@@ -1,90 +0,0 @@
import mongoose, {Document} from "mongoose";
import { Binary, ObjectID } from "mongodb";
const fileSchema = new mongoose.Schema({
length: {
type: Number,
required: true,
},
chunkSize: {
type: Number,
},
uploadDate: {
type: Date,
required: true
},
filename: {
type: String,
required: true
},
metadata: {
type: {
owner: {
type: String,
required: true
},
parent: {
type: String,
required: true
},
parentList: {
type: String,
required: true
},
hasThumbnail: {
type: Boolean,
required: true
},
isVideo: {
type: Boolean,
required: true
},
thumbnailID: String,
size: {
type: Number,
required: true,
},
IV: {
type: Binary,
required: true
},
linkType: String,
link: String,
filePath: String,
s3ID: String,
personalFile: Boolean,
},
required: true
}
})
export interface FileInterface extends Document {
length: number,
chunkSize: number,
uploadDate: string,
filename: string,
lastErrorObject: {updatedExisting: any}
metadata: {
owner: string | ObjectID,
parent: string,
parentList: string,
hasThumbnail: boolean,
isVideo: boolean,
thumbnailID?: string,
size: number,
IV: Buffer,
linkType?: 'one' | 'public',
link?: string,
filePath?: string,
s3ID?: string,
personalFile? : boolean
}
}
const File = mongoose.model<FileInterface>("fs.files", fileSchema);
export default File;
module.exports = File;
+57
View File
@@ -0,0 +1,57 @@
import mongoose, { Document } from "mongoose";
const folderSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
validate(value: any) {
if (!value || value.length === 0 || value.length >= 256) {
throw new Error(
"Name is required and length must be greater than 0 and 256 characters max"
);
}
},
},
parent: {
type: String,
required: true,
},
owner: {
type: String,
required: true,
},
parentList: {
type: Array,
required: true,
},
personalFolder: Boolean,
trashed: Boolean,
},
{
timestamps: true,
}
);
export interface FolderInterface
extends mongoose.Document<mongoose.Types.ObjectId> {
name: string;
parent: string;
owner: string;
createdAt: Date;
updatedAt: Date;
parentList: string[];
_doc?: any;
personalFolder?: boolean;
trashed: boolean | null;
}
folderSchema.index({ createdAt: 1 }, { background: true });
folderSchema.index({ owner: 1 }, { background: true });
folderSchema.index({ trashed: 1 }, { background: true });
folderSchema.index({ parent: 1 }, { background: true });
folderSchema.index({ name: 1 }, { background: true });
const Folder = mongoose.model<FolderInterface>("Folder", folderSchema);
export default Folder;
-43
View File
@@ -1,43 +0,0 @@
import mongoose, {Document} from "mongoose";
const folderSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
parent: {
type: String,
required: true,
},
owner: {
type: String,
required: true
},
parentList: {
type: Array,
required:true
},
personalFolder: Boolean
}, {
timestamps: true
})
export interface FolderInterface extends Document {
name: string,
parent: string,
owner: string,
createdAt: Date,
updatedAt: Date,
parentList: string[],
_doc?: any,
personalFolder?: boolean
}
const Folder = mongoose.model<FolderInterface>("Folder", folderSchema);
export default Folder;
+60
View File
@@ -0,0 +1,60 @@
import mongoose, { Document } from "mongoose";
const thumbnailSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
validate(value: any) {
if (!value || value.length === 0 || value.length >= 256) {
throw new Error(
"Name is required and length must be greater than 0 and 256 characters max"
);
}
},
},
owner: {
type: String,
required: true,
},
data: {
type: Buffer,
},
path: {
type: String,
},
IV: {
type: Buffer,
},
s3ID: String,
personalFile: String,
},
{
timestamps: true,
}
);
export interface ThumbnailInterface extends Document {
_id: any;
name: string;
owner: string;
data?: any;
path?: string;
IV: Buffer;
s3ID?: string;
personalFile?: boolean;
createdAt: Date;
updatedAt: Date;
}
thumbnailSchema.index({ owner: 1 });
const Thumbnail = mongoose.model<ThumbnailInterface>(
"Thumbnail",
thumbnailSchema
);
export default Thumbnail;
module.exports = Thumbnail;
-46
View File
@@ -1,46 +0,0 @@
import mongoose, {Document} from "mongoose";
const thumbnailSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
owner: {
type: String,
required: true
},
data: {
type: Buffer,
},
path: {
type: String
},
IV: {
type: Buffer,
},
s3ID: String,
personalFile: String,
}, {
timestamps: true
})
export interface ThumbnailInterface extends Document {
_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;
module.exports = Thumbnail;
+464
View File
@@ -0,0 +1,464 @@
import mongoose, { Document } from "mongoose";
import validator from "validator";
import crypto from "crypto";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import env from "../enviroment/env";
import NotAuthorizedError from "../utils/NotAuthorizedError";
const userSchema = new mongoose.Schema(
{
email: {
type: String,
required: true,
trim: true,
unique: true,
lowercase: true,
validate(value: any): any {
if (!validator.isEmail(value)) {
throw new Error("Email is invalid");
} else if (value.length > 320) {
throw new Error("Email length must be less than 320 characters");
} else if (value.length < 3) {
throw new Error("Email length must be at least 3 characters");
}
},
},
password: {
type: String,
trim: true,
required: true,
validate(value: any): any {
if (value.length < 6) {
throw new Error("Password length must be at least 6 characters");
} else if (value.length > 256) {
throw new Error("Password length must be less than 256 characters");
}
},
},
tokens: [
{
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: {
type: String,
},
publicKey: {
type: String,
},
emailVerified: {
type: Boolean,
},
emailToken: {
type: String,
},
passwordResetToken: {
type: String,
},
passwordLastModified: Number,
},
{
timestamps: true,
}
);
export interface UserInterface extends Document {
_id: mongoose.Types.ObjectId;
email: string;
password: string;
tokens: any[];
tempTokens: any[];
privateKey?: string;
publicKey?: string;
token?: string;
emailVerified?: boolean;
emailToken?: string;
passwordResetToken?: string;
passwordLastModified?: number;
getEncryptionKey: () => Buffer | undefined;
generateTempAuthToken: () => Promise<any>;
encryptToken: (tempToken: any, key: any, publicKey: any) => 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) => Promise<void>;
generateEmailVerifyToken: () => Promise<string>;
generatePasswordResetToken: () => Promise<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;
if (user.isModified("password")) {
user.password = await bcrypt.hash(user.password, 8);
}
next();
});
userSchema.statics.findByCreds = async (email: string, password: string) => {
const user = await User.findOne({ email });
if (!user) {
throw new NotAuthorizedError("User not found");
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
throw new NotAuthorizedError("Incorrect password");
}
return user;
};
userSchema.methods.toJSON = function () {
const user = this;
const userObject = user.toObject();
delete userObject.password;
delete userObject.tokens;
delete userObject.tempTokens;
delete userObject.privateKey;
delete userObject.publicKey;
if (env.emailVerification !== "true") {
delete userObject.emailVerified;
} else {
userObject.emailVerified = user.emailVerified || false;
}
return userObject;
};
userSchema.methods.generateAuthTokenStreamVideo = async function (
uuid: string | undefined
) {
const iv = crypto.randomBytes(16);
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(
accessTokenStreamVideo,
encryptionKey,
iv
);
uuid = uuid ? uuid : "unknown";
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,
email: user.email,
};
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);
uuid = uuid ? uuid : "unknown";
await User.updateOne(
{ _id: user._id },
{ $push: { tokens: { token: encryptedToken, uuid, time } } }
);
return { accessToken, refreshToken };
};
userSchema.methods.encryptToken = function (
token: string,
key: string,
iv: any
) {
iv = Buffer.from(iv, "hex");
const TOKEN_CIPHER_KEY = crypto.createHash("sha256").update(key).digest();
const cipher = crypto.createCipheriv("aes-256-cbc", TOKEN_CIPHER_KEY, iv);
const encryptedText = cipher.update(token);
return Buffer.concat([encryptedText, cipher.final()]).toString("hex");
};
userSchema.methods.decryptToken = function (
encryptedToken: any,
key: string,
iv: any
) {
encryptedToken = Buffer.from(encryptedToken, "hex");
iv = Buffer.from(iv, "hex");
const TOKEN_CIPHER_KEY = crypto.createHash("sha256").update(key).digest();
const decipher = crypto.createDecipheriv("aes-256-cbc", TOKEN_CIPHER_KEY, iv);
const tokenDecrypted = decipher.update(encryptedToken);
return Buffer.concat([tokenDecrypted, decipher.final()]).toString();
};
userSchema.methods.generateEncryptionKeys = async function () {
const user = this;
const userPassword = user.password;
const masterPassword = env.key!;
const randomKey = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
const USER_CIPHER_KEY = crypto
.createHash("sha256")
.update(userPassword)
.digest();
const cipher = crypto.createCipheriv("aes-256-cbc", USER_CIPHER_KEY, iv);
let encryptedText = cipher.update(randomKey);
encryptedText = Buffer.concat([encryptedText, cipher.final()]);
const MASTER_CIPHER_KEY = crypto
.createHash("sha256")
.update(masterPassword)
.digest();
const masterCipher = crypto.createCipheriv(
"aes-256-cbc",
MASTER_CIPHER_KEY,
iv
);
const masterEncryptedText = masterCipher.update(encryptedText);
user.privateKey = Buffer.concat([
masterEncryptedText,
masterCipher.final(),
]).toString("hex");
user.publicKey = iv.toString("hex");
await user.save();
};
userSchema.methods.getEncryptionKey = function () {
try {
const user = this;
const userPassword = user.password;
const masterEncryptedText = user.privateKey;
const masterPassword = env.key!;
const iv = Buffer.from(user.publicKey, "hex");
const USER_CIPHER_KEY = crypto
.createHash("sha256")
.update(userPassword)
.digest();
const MASTER_CIPHER_KEY = crypto
.createHash("sha256")
.update(masterPassword)
.digest();
const unhexMasterText = Buffer.from(masterEncryptedText, "hex");
const masterDecipher = crypto.createDecipheriv(
"aes-256-cbc",
MASTER_CIPHER_KEY,
iv
);
let masterDecrypted = masterDecipher.update(unhexMasterText);
masterDecrypted = Buffer.concat([masterDecrypted, masterDecipher.final()]);
let decipher = crypto.createDecipheriv("aes-256-cbc", USER_CIPHER_KEY, iv);
let decrypted = decipher.update(masterDecrypted);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted;
} catch (e) {
console.log("Get Encryption Key Error", e);
return undefined;
}
};
userSchema.methods.changeEncryptionKey = async function (randomKey: Buffer) {
const user = this;
const userPassword = user.password;
const masterPassword = env.key!;
const iv = crypto.randomBytes(16);
const USER_CIPHER_KEY = crypto
.createHash("sha256")
.update(userPassword)
.digest();
const cipher = crypto.createCipheriv("aes-256-cbc", USER_CIPHER_KEY, iv);
let encryptedText = cipher.update(randomKey);
encryptedText = Buffer.concat([encryptedText, cipher.final()]);
const MASTER_CIPHER_KEY = crypto
.createHash("sha256")
.update(masterPassword)
.digest();
const masterCipher = crypto.createCipheriv(
"aes-256-cbc",
MASTER_CIPHER_KEY,
iv
);
const masterEncryptedText = masterCipher.update(encryptedText);
user.privateKey = Buffer.concat([
masterEncryptedText,
masterCipher.final(),
]).toString("hex");
user.publicKey = iv.toString("hex");
await user.save();
};
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.passwordAccess!,
{ expiresIn: "3000ms" }
);
const encryptionKey = user.getEncryptionKey();
const encryptedToken = user.encryptToken(token, encryptionKey, iv);
user.tempTokens = user.tempTokens.concat({ token: encryptedToken });
await user.save();
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.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.passwordAccess!,
{ expiresIn: "5h" }
);
const encryptionKey = user.getEncryptionKey();
const encryptedToken = user.encryptToken(token, encryptionKey, iv);
user.tempTokens = user.tempTokens.concat({ token: encryptedToken });
await user.save();
return token;
};
const User = mongoose.model<UserInterface>("User", userSchema);
export default User;
module.exports = User;
-610
View File
@@ -1,610 +0,0 @@
import mongoose, {Document} from "mongoose";
import validator from "validator";
import crypto from "crypto";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import env from "../enviroment/env";
const userSchema = new mongoose.Schema({
name:
{
type:String,
},
email: {
type: String,
required: true,
trim: true,
unique: true,
lowercase: true,
validate(value: any): any {
if (!validator.isEmail(value)) {
throw new Error("Email is invalid");
}
}
},
password: {
type: String,
trim: true,
required: true,
validate(value: any): any {
if (value.length < 6) {
throw new Error("Password Length Not Sufficent");
}
}
},
tokens:[{
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: {
type: String,
},
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
})
export interface UserInterface extends Document {
_id: string,
name: string,
email: string,
password: string,
tokens: any[],
tempTokens: any[],
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: () => Promise<any>;
encryptToken: (tempToken: any, key: any, publicKey: any) => 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) => 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;
if (user.isModified("password")) {
user.password = await bcrypt.hash(user.password, 8);
}
next();
})
userSchema.statics.findByCreds = async(email: string, password: string) => {
const user = await User.findOne({email});
if (!user) {
throw new Error("User not found")
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
throw new Error("Incorrect password");
}
return user;
}
userSchema.methods.toJSON = function() {
const user = this;
const userObject = user.toObject();
delete userObject.password;
delete userObject.tokens;
delete userObject.tempTokens;
delete userObject.privateKey;
delete userObject.publicKey;
return userObject;
}
userSchema.methods.generateAuthTokenStreamVideo = async function(uuid: string | undefined) {
const iv = crypto.randomBytes(16);
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(accessTokenStreamVideo, encryptionKey, iv);
uuid = uuid ? uuid : "unknown";
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) {
iv = Buffer.from(iv, "hex")
const TOKEN_CIPHER_KEY = crypto.createHash('sha256').update(key).digest();
const cipher = crypto.createCipheriv('aes-256-cbc', TOKEN_CIPHER_KEY, iv);
const encryptedText = cipher.update(token);
return Buffer.concat([encryptedText, cipher.final()]).toString("hex");;
}
userSchema.methods.decryptToken = function(encryptedToken: any, key: string, iv: any) {
encryptedToken = Buffer.from(encryptedToken, "hex");
iv = Buffer.from(iv, "hex")
const TOKEN_CIPHER_KEY = crypto.createHash('sha256').update(key).digest();
const decipher = crypto.createDecipheriv('aes-256-cbc', TOKEN_CIPHER_KEY, iv)
const tokenDecrypted = decipher.update(encryptedToken);
return Buffer.concat([tokenDecrypted, decipher.final()]).toString();
}
userSchema.methods.generateEncryptionKeys = async function() {
const user = this;
const userPassword = user.password;
const masterPassword = env.key!;
const randomKey = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
const USER_CIPHER_KEY = crypto.createHash('sha256').update(userPassword).digest();
const cipher = crypto.createCipheriv('aes-256-cbc', USER_CIPHER_KEY, iv);
let encryptedText = cipher.update(randomKey);
encryptedText = Buffer.concat([encryptedText, cipher.final()]);
const MASTER_CIPHER_KEY = crypto.createHash('sha256').update(masterPassword).digest();
const masterCipher = crypto.createCipheriv('aes-256-cbc', MASTER_CIPHER_KEY, iv);
const masterEncryptedText = masterCipher.update(encryptedText);
user.privateKey = Buffer.concat([masterEncryptedText, masterCipher.final()]).toString("hex");
user.publicKey = iv.toString("hex");
await user.save();
}
userSchema.methods.getEncryptionKey = function() {
try {
const user = this;
const userPassword = user.password;
const masterEncryptedText = user.privateKey;
const masterPassword = env.key!;
const iv = Buffer.from(user.publicKey, "hex");
const USER_CIPHER_KEY = crypto.createHash('sha256').update(userPassword).digest();
const MASTER_CIPHER_KEY = crypto.createHash('sha256').update(masterPassword).digest();
const unhexMasterText = Buffer.from(masterEncryptedText, "hex");
const masterDecipher = crypto.createDecipheriv('aes-256-cbc', MASTER_CIPHER_KEY, iv)
let masterDecrypted = masterDecipher.update(unhexMasterText);
masterDecrypted = Buffer.concat([masterDecrypted, masterDecipher.final()])
let decipher = crypto.createDecipheriv('aes-256-cbc', USER_CIPHER_KEY, iv);
let decrypted = decipher.update(masterDecrypted);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted;
} catch (e) {
console.log("Get Encryption Key Error", e);
return undefined;
}
}
userSchema.methods.changeEncryptionKey = async function(randomKey: Buffer) {
const user = this;
const userPassword = user.password;
const masterPassword = env.key!;
const iv = crypto.randomBytes(16);
const USER_CIPHER_KEY = crypto.createHash('sha256').update(userPassword).digest();
const cipher = crypto.createCipheriv('aes-256-cbc', USER_CIPHER_KEY, iv);
let encryptedText = cipher.update(randomKey);
encryptedText = Buffer.concat([encryptedText, cipher.final()]);
const MASTER_CIPHER_KEY = crypto.createHash('sha256').update(masterPassword).digest();
const masterCipher = crypto.createCipheriv('aes-256-cbc', MASTER_CIPHER_KEY, iv);
const masterEncryptedText = masterCipher.update(encryptedText);
user.privateKey = Buffer.concat([masterEncryptedText, masterCipher.final()]).toString("hex");
user.publicKey = iv.toString("hex");
await user.save();
}
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.passwordAccess!, {expiresIn: "3000ms"});
const encryptionKey = user.getEncryptionKey();
const encryptedToken = user.encryptToken(token, encryptionKey, iv);
user.tempTokens = user.tempTokens.concat({token: encryptedToken});
await user.save();
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.passwordAccess!, {expiresIn:"5h"});
const encryptionKey = user.getEncryptionKey();
const encryptedToken = user.encryptToken(token, encryptionKey, iv);
user.tempTokens = user.tempTokens.concat({token: encryptedToken});
await user.save();
return token;
}
const User = mongoose.model<UserInterface>("User", userSchema);
export default User;
module.exports = User;
+36
View File
@@ -0,0 +1,36 @@
import getEnvVariables from "../enviroment/get-env-variables";
getEnvVariables();
import getKey from "../key/get-key";
import servers from "./server";
const { server, serverHttps } = servers;
const serverStart = async () => {
await getKey();
console.log("ENV", process.env.NODE_ENV);
if (process.env.NODE_ENV === "production" && process.env.SSL === "true") {
server.listen(process.env.HTTP_PORT, process.env.URL, () => {
console.log("Http Server Running On Port:", process.env.HTTP_PORT);
});
serverHttps.listen(process.env.HTTPS_PORT, function () {
console.log("Https Server Running On Port:", process.env.HTTPS_PORT);
});
} else if (process.env.NODE_ENV === "production") {
const port = process.env.HTTP_PORT || process.env.PORT;
server.listen(port, process.env.URL, () => {
console.log("Http Server (No-SSL) Running On Port:", port);
});
} else {
const port = process.env.HTTP_PORT || process.env.PORT;
server.listen(port, process.env.URL, () => {
console.log("\nDevelopment Backend Server Running On :", port);
});
}
};
serverStart();
+41 -39
View File
@@ -1,14 +1,8 @@
import express, {Request, Response} from "express";
import express, { Request, Response } from "express";
import path from "path";
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 userRouter from "../express-routers/user-router";
import fileRouter from "../express-routers/file-router";
import folderRouter from "../express-routers/folder-router";
import bodyParser from "body-parser";
import https from "https";
import fs from "fs";
@@ -18,60 +12,68 @@ import compression from "compression";
import http from "http";
import cookieParser from "cookie-parser";
import env from "../enviroment/env";
import { middlewareErrorHandler } from "../middleware/utils/middleware-utils";
import cors from "cors";
// import requestIp from "request-ip";
const app = express();
const publicPath = path.join(__dirname, "..", "..", "public");
const publicPath = path.join(__dirname, "..", "..", "dist-frontend");
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");
if (process.env.SSL === "true") {
const cert = fs.readFileSync("certificate.crt");
const ca = fs.readFileSync("certificate.ca-bundle");
const key = fs.readFileSync("certificate.key");
const options = {
cert,
ca,
key,
};
const options = {
cert,
ca,
key
}
serverHttps = https.createServer( options, app );
serverHttps = https.createServer(options, app);
}
server = http.createServer(app);
require("../db/mongoose");
require("../db/connections/mongoose");
app.use(cors());
app.use(cookieParser(env.passwordCookie));
app.use(helmet())
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(express.static(publicPath, { index: false }));
app.use(bodyParser.json({ limit: "50mb" }));
app.use(
bodyParser.urlencoded({
limit: "50mb",
extended: true,
parameterLimit: 50000,
})
);
// app.use(requestIp.mw());
app.use(busboy({
app.use(
busboy({
highWaterMark: 2 * 1024 * 1024,
}));
})
);
app.use(userRouter, fileRouter, folderRouter, storageRouter, googleFileRouter, personalFileRouter, googleFolderRouter, userPersonalRouter, userGoogleRouter);
app.use(userRouter, fileRouter, folderRouter);
app.use(middlewareErrorHandler);
//const nodeMode = process.env.NODE_ENV ? "Production" : "Development/Testing";
//console.log("Node Enviroment Mode:", nodeMode);
if (process.env.NODE_ENV === "production") {
app.get("*", (_: Request, res: Response) => {
res.sendFile(path.join(publicPath, "index.html"));
});
}
app.get("*", (_: Request, res: Response) => {
res.sendFile(path.join(publicPath, "index.html"))
})
export default {server, serverHttps};
export default { server, serverHttps };
-42
View File
@@ -1,42 +0,0 @@
import getEnvVariables from "../enviroment/getEnvVariables";
getEnvVariables();
import getKey from "../key/getKey";
import servers from "./server";
const {server, serverHttps} = servers;
const serverStart = async() => {
await getKey();
console.log("ENV", process.env.NODE_ENV);
if (process.env.NODE_ENV === 'production' && process.env.SSL === "true") {
server.listen(process.env.HTTP_PORT,process.env.URL, () => {
console.log("Http Server Running On Port:", process.env.HTTP_PORT);
})
serverHttps.listen(process.env.HTTPS_PORT, function () {
console.log( 'Https Server Running On Port:', process.env.HTTPS_PORT);
} );
} else if (process.env.NODE_ENV === 'production') {
const port = process.env.HTTP_PORT || process.env.PORT;
server.listen(port, process.env.URL, () => {
console.log("Http Server (No-SSL) Running On Port:", port);
})
} else {
const port = process.env.HTTP_PORT || process.env.PORT;
server.listen(port, process.env.URL, () => {
console.log("Development Server Running On Port:", port);
})
}
}
serverStart();
@@ -1,499 +0,0 @@
import { Response, Request } from "express";
import ChunkInterface from "./utils/ChunkInterface";
import { UserInterface } from "../../models/user";
import NotAuthorizedError from "../../utils/NotAuthorizedError";
import NotFoundError from "../../utils/NotFoundError";
import crypto from "crypto";
import getBusboyData from "./utils/getBusboyData";
import videoChecker from "../../utils/videoChecker";
import fs from "fs";
import uuid from "uuid";
import awaitUploadStreamFS from "./utils/awaitUploadStreamFS";
import File, { FileInterface } from "../../models/file";
import getFileSize from "./utils/getFileSize";
import DbUtilFile from "../../db/utils/fileUtils/index";
import awaitStream from "./utils/awaitStream";
import createThumbnailAny from "./utils/createThumbailAny";
import imageChecker from "../../utils/imageChecker";
import Thumbnail, {ThumbnailInterface} from "../../models/thumbnail";
import streamToBuffer from "../../utils/streamToBuffer";
import User from "../../models/user";
import env from "../../enviroment/env";
import removeChunksFS from "./utils/removeChunksFS";
import getPrevIVFS from "./utils/getPrevIVFS";
import awaitStreamVideo from "./utils/awaitStreamVideo";
import fixStartChunkLength from "./utils/fixStartChunkLength";
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();
class FileSystemService implements ChunkInterface {
constructor() {
}
uploadFile = async(user: UserInterface, busboy: any, req: Request) => {
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 {file, filename, formData} = await getBusboyData(busboy);
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 = {
owner: user._id,
parent,
parentList,
hasThumbnail,
thumbnailID,
isVideo,
size,
IV: initVect,
filePath: env.fsDirectory + systemFileName
}
const fileWriteStream = fs.createWriteStream(metadata.filePath);
const totalStreamsToErrorCatch = [file, cipher, fileWriteStream];
await awaitUploadStreamFS(file.pipe(cipher), fileWriteStream, req, metadata.filePath, totalStreamsToErrorCatch);
const date = new Date();
const encryptedFileSize = await getFileSize(metadata.filePath);
const currentFile = new File({
filename,
uploadDate: date.toISOString(),
length: encryptedFileSize,
metadata
});
await currentFile.save();
await addToStoageSize(user, size, personalFile);
const imageCheck = imageChecker(currentFile.filename);
if (currentFile.length < 15728640 && imageCheck) {
const updatedFile = await createThumbnailAny(currentFile, filename, user);
return updatedFile;
} else {
return currentFile;
}
}
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);
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);
res.set('Content-Type', 'binary/octet-stream');
res.set('Content-Disposition', 'attachment; filename="' + currentFile.filename + '"');
res.set('Content-Length', currentFile.metadata.size.toString());
const allStreamsToErrorCatch = [readStream, decipher];
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 ForbiddenError("Invalid Encryption Key")
const thumbnail = await Thumbnail.findById(new ObjectID(id)) as ThumbnailInterface;
if (thumbnail.owner !== user._id.toString()) {
throw new ForbiddenError('Thumbnail Unauthorized Error');
}
const iv = thumbnail.IV!;
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
const decipher = crypto.createDecipheriv("aes256", CIPHER_KEY, iv);
const readStream = fs.createReadStream(thumbnail.path!);
const allStreamsToErrorCatch = [readStream, decipher];
const bufferData = await streamToBuffer(readStream.pipe(decipher), allStreamsToErrorCatch);
return bufferData;
}
getFullThumbnail = async(user: UserInterface, fileID: string, res: Response) => {
const userID = user._id;
const file: FileInterface = await dbUtilsFile.getFileInfo(fileID, userID);
if (!file) throw new NotFoundError("File Thumbnail Not Found");
const password = user.getEncryptionKey();
const IV = file.metadata.IV.buffer as Buffer;
if (!password) throw new ForbiddenError("Invalid Encryption Key")
const readStream = fs.createReadStream(file.metadata.filePath!);
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV);
res.set('Content-Type', 'binary/octet-stream');
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
res.set('Content-Length', file.metadata.size.toString());
const allStreamsToErrorCatch = [readStream, decipher];
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
}
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);
if (!currentFile) throw new NotFoundError("Video File Not Found");
const password = user.getEncryptionKey();
if (!password) throw new ForbiddenError("Invalid Encryption Key")
const fileSize = currentFile.metadata.size;
const range = headers.range
const parts = range.replace(/bytes=/, "").split("-")
let start = parseInt(parts[0], 10)
let end = parts[1]
? parseInt(parts[1], 10)
: fileSize-1
const IV = currentFile.metadata.IV.buffer as Buffer;
const chunksize = (end-start)+1
let head = {
'Content-Range': 'bytes ' + start + '-' + end + '/' + fileSize,
'Accept-Ranges': 'bytes',
'Content-Length': chunksize,
'Content-Type': 'video/mp4'}
let currentIV = IV;
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;
}
// 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,
});
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 = [readStream, decipher];
readStream.pipe(decipher);
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, allStreamsToErrorCatch, readStream);
readStream.destroy();
}
getPublicDownload = async(fileID: string, tempToken: any, res: Response) => {
const file: FileInterface = await dbUtilsFile.getPublicFile(fileID);
if (!file || !file.metadata.link || file.metadata.link !== tempToken) {
throw new NotAuthorizedError("File Not Public");
}
const user = await User.findById(file.metadata.owner) as UserInterface;
const password = user.getEncryptionKey();
if (!password) throw new ForbiddenError("Invalid Encryption Key");
const IV = file.metadata.IV.buffer as Buffer;
const readStream = fs.createReadStream(file.metadata.filePath!);
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV);
res.set('Content-Type', 'binary/octet-stream');
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
res.set('Content-Length', file.metadata.size.toString());
const allStreamsToErrorCatch = [readStream, decipher];
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
if (file.metadata.linkType === "one") {
await dbUtilsFile.removeOneTimePublicLink(fileID);
}
}
deleteFile = async(userID: string, fileID: string) => {
const file: FileInterface = await dbUtilsFile.getFileInfo(fileID, userID);
if (!file) throw new NotFoundError("Delete File Not Found Error");
if (file.metadata.thumbnailID) {
const thumbnail = await Thumbnail.findById(file.metadata.thumbnailID) as ThumbnailInterface;
const thumbnailPath = thumbnail.path!;
await removeChunksFS(thumbnailPath);
await Thumbnail.deleteOne({_id: file.metadata.thumbnailID});
}
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[]) => {
const parentListString = parentList.toString()
await Folder.deleteMany({"owner": userID, "parentList": { $all: parentList}})
await Folder.deleteMany({"owner": userID, "_id": folderID});
const fileList = await dbUtilsFile.getFileListByParent(userID, parentListString);
if (!fileList) throw new NotFoundError("Delete File List Not Found");
for (let i = 0; i < fileList.length; i++) {
const currentFile = fileList[i];
try {
if (currentFile.metadata.thumbnailID) {
const thumbnail = await Thumbnail.findById(currentFile.metadata.thumbnailID) as ThumbnailInterface;
const thumbnailPath = thumbnail.path!;
await removeChunksFS(thumbnailPath);
await Thumbnail.deleteOne({_id: currentFile.metadata.thumbnailID});
}
await removeChunksFS(currentFile.metadata.filePath!);
await File.deleteOne({_id: currentFile._id});
} catch (e) {
console.log("Could not delete file", currentFile.filename, currentFile._id);
}
}
}
deleteAll = async(userID: string) => {
await Folder.deleteMany({"owner": userID});
const fileList = await dbUtilsFile.getFileListByOwner(userID);
if (!fileList) throw new NotFoundError("Delete All File List Not Found Error");
for (let i = 0; i < fileList.length; i++) {
const currentFile = fileList[i];
try {
if (currentFile.metadata.thumbnailID) {
const thumbnail = await Thumbnail.findById(currentFile.metadata.thumbnailID) as ThumbnailInterface;
const thumbnailPath = thumbnail.path!;
await removeChunksFS(thumbnailPath);
await Thumbnail.deleteOne({_id: currentFile.metadata.thumbnailID});
}
await removeChunksFS(currentFile.metadata.filePath!);
await File.deleteOne({_id: currentFile._id});
} catch (e) {
console.log("Could Not Remove File", currentFile.filename, currentFile._id);
}
}
}
}
export default FileSystemService;
@@ -1,486 +0,0 @@
import mongoose from "../../db/mongoose";
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 createThumbnailAny from "./utils/createThumbailAny";
import Thumbnail, {ThumbnailInterface} from "../../models/thumbnail";
import NotAuthorizedError from "../../utils/NotAuthorizedError";
import NotFoundError from "../../utils/NotFoundError";
import {GridFSBucketWriteStream} from "mongodb";
import awaitStream from "./utils/awaitStream";
import awaitUploadStream from "./utils/awaitUploadStream";
import User, { UserInterface } from "../../models/user";
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;
const dbUtilsFile = new DbUtilFile();
class MongoService implements ChunkInterface {
constructor() {
}
uploadFile = async(user: UserInterface, busboy: any, req: Request) => {
const password = user.getEncryptionKey();
if (!password) throw new ForbiddenError("Invalid Encryption Key")
let bucketStream: GridFSBucketWriteStream;
const initVect = crypto.randomBytes(16);
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
const cipher = crypto.createCipheriv('aes256', CIPHER_KEY, initVect);
const {file, filename, formData} = await getBusboyData(busboy);
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,
parentList,
hasThumbnail,
thumbnailID,
isVideo,
size,
IV: initVect
}
let bucket = new mongoose.mongo.GridFSBucket(conn.db);
bucketStream = bucket.openUploadStream(filename, {metadata});
const allStreamsToErrorCatch = [file, cipher, bucketStream];
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 createThumbnailAny(finishedFile, filename, user);
return updatedFile;
} else {
return finishedFile;
}
}
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);
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);
res.set('Content-Type', 'binary/octet-stream');
res.set('Content-Disposition', 'attachment; filename="' + currentFile.filename + '"');
res.set('Content-Length', currentFile.metadata.size.toString());
const allStreamsToErrorCatch = [readStream, decipher];
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 ForbiddenError("Invalid Encryption Key")
const thumbnail = await Thumbnail.findById(new ObjectID(id)) as ThumbnailInterface;
if (thumbnail.owner !== user._id.toString()) {
throw new ForbiddenError('Thumbnail Unauthorized Error');
}
const iv = thumbnail.data.slice(0, 16);
const chunk = thumbnail.data.slice(16);
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
const decipher = crypto.createDecipheriv("aes256", CIPHER_KEY, iv);
const decryptedThumbnail = Buffer.concat([decipher.update(chunk), decipher.final()]);
return decryptedThumbnail;
}
getFullThumbnail = async(user: UserInterface, fileID: string, res: Response) => {
const userID = user._id;
const file = await dbUtilsFile.getFileInfo(fileID, userID);
if (!file) throw new NotFoundError("File Thumbnail Not Found");
const bucket = new mongoose.mongo.GridFSBucket(conn.db);
const password = user.getEncryptionKey();
const IV = file.metadata.IV.buffer as Buffer;
if (!password) throw new ForbiddenError("Invalid Encryption Key")
const readStream = bucket.openDownloadStream(new ObjectID(fileID))
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV);
res.set('Content-Type', 'binary/octet-stream');
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
res.set('Content-Length', file.metadata.size.toString());
const allStreamsToErrorCatch = [readStream, decipher];
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
}
getPublicDownload = async(fileID: string, tempToken: any, res: Response) => {
const file = await dbUtilsFile.getPublicFile(fileID);
if (!file || !file.metadata.link || file.metadata.link !== tempToken) {
throw new NotAuthorizedError("File Not Public");
}
const user = await User.findById(file.metadata.owner) as UserInterface;
const password = user.getEncryptionKey();
if (!password) throw new ForbiddenError("Invalid Encryption Key");
const bucket = new mongoose.mongo.GridFSBucket(conn.db);
const IV = file.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);
res.set('Content-Type', 'binary/octet-stream');
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
res.set('Content-Length', file.metadata.size.toString());
const allStreamsToErrorCatch = [readStream, decipher];
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
if (file.metadata.linkType === "one") {
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);
if (!currentFile) throw new NotFoundError("Video File Not Found");
const password = user.getEncryptionKey();
if (!password) throw new ForbiddenError("Invalid Encryption Key")
const fileSize = currentFile.metadata.size;
const range = headers.range
const parts = range.replace(/bytes=/, "").split("-")
let start = parseInt(parts[0], 10)
let end = parts[1]
? parseInt(parts[1], 10)
: fileSize-1
const chunksize = (end-start)+1
const IV = currentFile.metadata.IV.buffer as Buffer;
let head = {
'Content-Range': 'bytes ' + start + '-' + end + '/' + fileSize,
'Accept-Ranges': 'bytes',
'Content-Length': chunksize,
'Content-Type': 'video/mp4'}
let currentIV = IV;
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;
}
// 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, {
});
const readStream = bucket.openDownloadStream(new ObjectID(fileID), {
start: fixedStart,
end: fixedEnd,
});
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
res.writeHead(206, head);
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, currentIV);
decipher.setAutoPadding(false);
const allStreamsToErrorCatch = [readStream, decipher];
readStream.pipe(decipher);
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, allStreamsToErrorCatch, readStream);
readStream.destroy();
}
deleteFile = async(userID: string, fileID: string) => {
let bucket = new mongoose.mongo.GridFSBucket(conn.db, {
chunkSizeBytes: 1024 * 255,
});
const file = await dbUtilsFile.getFileInfo(fileID, userID);
if (!file) throw new NotFoundError("Delete File Not Found Error");
if (file.metadata.thumbnailID) {
await Thumbnail.deleteOne({_id: file.metadata.thumbnailID});
}
await bucket.delete(new ObjectID(fileID));
await subtractFromStorageSize(userID, file.length, file.metadata.personalFile!);
}
deleteFolder = async(userID: string, folderID: string, parentList: string[]) => {
let bucket = new mongoose.mongo.GridFSBucket(conn.db, {
chunkSizeBytes: 1024 * 255
});
const parentListString = parentList.toString()
await Folder.deleteMany({"owner": userID, "parentList": { $all: parentList}})
await Folder.deleteMany({"owner": userID, "_id": folderID});
const fileList = await dbUtilsFile.getFileListByParent(userID, parentListString);
if (!fileList) throw new NotFoundError("Delete File List Not Found");
for (let i = 0; i < fileList.length; i++) {
const currentFile = fileList[i];
try {
if (currentFile.metadata.thumbnailID) {
await Thumbnail.deleteOne({_id: currentFile.metadata.thumbnailID});
}
await bucket.delete(new ObjectID(currentFile._id));
} catch (e) {
console.log("Could not delete file", currentFile.filename, currentFile._id);
}
}
}
deleteAll = async(userID: string) => {
let bucket = new mongoose.mongo.GridFSBucket(conn.db, {
chunkSizeBytes: 1024 * 255
});
await Folder.deleteMany({"owner": userID});
const fileList = await dbUtilsFile.getFileListByOwner(userID);
if (!fileList) throw new NotFoundError("Delete All File List Not Found Error");
for (let i = 0; i < fileList.length; i++) {
const currentFile = fileList[i];
try {
if (currentFile.metadata.thumbnailID) {
await Thumbnail.deleteOne({_id: currentFile.metadata.thumbnailID})
}
await bucket.delete(new ObjectID(currentFile._id));
} catch (e) {
console.log("Could Not Remove File", currentFile.filename, currentFile._id);
}
}
}
}
export default MongoService;
-573
View File
@@ -1,573 +0,0 @@
import File, { FileInterface } from "../../models/file";
import User, {UserInterface} from "../../models/user";
import s3 from "../../db/s3";
import env from "../../enviroment/env";
import { Response, Request } from "express";
import ChunkInterface from "./utils/ChunkInterface";
import NotAuthorizedError from "../../utils/NotAuthorizedError";
import NotFoundError from "../../utils/NotFoundError";
import crypto from "crypto";
import getBusboyData from "./utils/getBusboyData";
import videoChecker from "../../utils/videoChecker";
import uuid from "uuid";
import awaitUploadStreamS3 from "./utils/awaitUploadStreamS3";
import awaitStream from "./utils/awaitStream";
import createThumbnailAny from "./utils/createThumbailAny";
import imageChecker from "../../utils/imageChecker";
import Thumbnail, {ThumbnailInterface} from "../../models/thumbnail";
import streamToBuffer from "../../utils/streamToBuffer";
import removeChunksS3 from "./utils/removeChunksS3";
import fixStartChunkLength from "./utils/fixStartChunkLength";
import fixEndChunkLength from "./utils/fixEndChunkLength";
import getPrevIVS3 from "./utils/getPrevIVS3";
import awaitStreamVideo from "./utils/awaitStreamVideo";
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 {
constructor() {
}
uploadFile = async(user: UserInterface, busboy: any, req: Request) => {
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 {file, filename, formData} = await getBusboyData(busboy);
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 s3Data: any = personalFile ? await user.decryptS3Data() : {};
const bucketName = personalFile ? s3Data.bucket : env.s3Bucket;
let metadata: any = {
owner: user._id,
parent,
parentList,
hasThumbnail,
thumbnailID,
isVideo,
size,
IV: initVect,
s3ID: randomS3ID,
}
if (personalFile) metadata = {...metadata, personalFile: true}
const params = {
Bucket: bucketName,
Body : file.pipe(cipher),
Key : randomS3ID
};
await awaitUploadStreamS3(params, personalFile, s3Data);
const date = new Date();
const encryptedFileSize = size;
const currentFile = new File({
filename,
uploadDate: date.toISOString(),
length: encryptedFileSize,
metadata
});
await currentFile.save();
await addToStoageSize(user, size, personalFile);
const imageCheck = imageChecker(currentFile.filename);
if (currentFile.length < 15728640 && imageCheck) {
const updatedFile = await createThumbnailAny(currentFile, filename, user);
return updatedFile;
} else {
return currentFile;
}
}
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);
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);
res.set('Content-Type', 'binary/octet-stream');
res.set('Content-Disposition', 'attachment; filename="' + currentFile.filename + '"');
res.set('Content-Length', currentFile.metadata.size.toString());
const params: any = {Bucket: bucket, Key: currentFile.metadata.s3ID!};
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);
if (!currentFile) throw new NotFoundError("Video File Not Found");
const password = user.getEncryptionKey();
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("-")
let start = parseInt(parts[0], 10)
let end = parts[1]
? parseInt(parts[1], 10)
: fileSize-1
const chunksize = (end-start)+1
const IV = currentFile.metadata.IV.buffer as Buffer;
let head = {
'Content-Range': 'bytes ' + start + '-' + end + '/' + fileSize,
'Accept-Ranges': 'bytes',
'Content-Length': chunksize,
'Content-Type': 'video/mp4'}
let currentIV = IV;
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;
}
// 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!, isPersonal, user) as Buffer;
}
const {s3Storage, bucket} = await this.getS3Auth(currentFile, user);
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);
await awaitStreamVideo(start, end, differenceStart, decipher, res, req, allStreamsToErrorCatch, s3ReadStream);
s3ReadStream.destroy();
}
getThumbnail = async(user: UserInterface, id: string) => {
const password = user.getEncryptionKey();
if (!password) throw new ForbiddenError("Invalid Encryption Key")
const thumbnail = await Thumbnail.findById(new ObjectID(id)) as ThumbnailInterface;
if (thumbnail.owner !== user._id.toString()) {
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: bucket, Key: thumbnail.s3ID!};
const readStream = s3Storage.getObject(params).createReadStream();
const allStreamsToErrorCatch = [readStream, decipher];
const bufferData = await streamToBuffer(readStream.pipe(decipher), allStreamsToErrorCatch);
return bufferData;
}
getFullThumbnail = async(user: UserInterface, fileID: string, res: Response) => {
const userID = user._id;
const file: FileInterface = await dbUtilsFile.getFileInfo(fileID, userID);
if (!file) throw new NotFoundError("File Thumbnail Not Found");
const password = user.getEncryptionKey();
const IV = file.metadata.IV.buffer as Buffer;
if (!password) throw new ForbiddenError("Invalid Encryption Key")
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()
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV);
res.set('Content-Type', 'binary/octet-stream');
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
res.set('Content-Length', file.metadata.size.toString());
const allStreamsToErrorCatch = [readStream, decipher];
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
}
getPublicDownload = async(fileID: string, tempToken: any, res: Response) => {
const file: FileInterface = await dbUtilsFile.getPublicFile(fileID);
if (!file || !file.metadata.link || file.metadata.link !== tempToken) {
throw new NotAuthorizedError("File Not Public");
}
const user = await User.findById(file.metadata.owner) as UserInterface;
const password = user.getEncryptionKey();
if (!password) throw new ForbiddenError("Invalid Encryption Key");
const IV = file.metadata.IV.buffer as Buffer;
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()
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV);
res.set('Content-Type', 'binary/octet-stream');
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
res.set('Content-Length', file.metadata.size.toString());
const allStreamsToErrorCatch = [readStream, decipher];
await awaitStream(readStream.pipe(decipher), res, allStreamsToErrorCatch);
if (file.metadata.linkType === "one") {
await dbUtilsFile.removeOneTimePublicLink(fileID);
}
}
deleteFile = async(userID: string, fileID: string) => {
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: bucket, Key: thumbnail.s3ID!};
await removeChunksS3(s3Storage, paramsThumbnail);
await Thumbnail.deleteOne({_id: file.metadata.thumbnailID});
}
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[]) => {
const parentListString = parentList.toString()
await Folder.deleteMany({"owner": userID, "parentList": { $all: parentList}})
await Folder.deleteMany({"owner": userID, "_id": folderID});
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: bucket, Key: thumbnail.s3ID!};
await removeChunksS3(s3Storage, paramsThumbnail);
await Thumbnail.deleteOne({_id: currentFile.metadata.thumbnailID});
}
const params: any = {Bucket: bucket, Key: currentFile.metadata.s3ID!};
await removeChunksS3(s3Storage, params);
await File.deleteOne({_id: currentFile._id});
} catch (e) {
console.log("Could not delete file", currentFile.filename, currentFile._id);
}
}
}
deleteAll = async(userID: string) => {
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: bucket, Key: thumbnail.s3ID!};
await removeChunksS3(s3Storage, paramsThumbnail);
await Thumbnail.deleteOne({_id: currentFile.metadata.thumbnailID});
}
const params: any = {Bucket: bucket, Key: currentFile.metadata.s3ID!};
await removeChunksS3(s3Storage, params);
await File.deleteOne({_id: currentFile._id});
} catch (e) {
console.log("Could Not Remove File", currentFile.filename, currentFile._id);
}
}
}
}
export default S3Service;
@@ -1,15 +0,0 @@
import { UserInterface } from "../../../models/user";
import { FileInterface } from "../../../models/file";
import { Request, Response } from "express";
interface ChunkInterface {
uploadFile: (user: UserInterface, busboy: any, req: Request) => Promise<FileInterface>;
downloadFile: (user: UserInterface, fileID: string, res: Response) => void;
getThumbnail: (user: UserInterface, id: string) => Promise<Buffer>;
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;
@@ -1,20 +0,0 @@
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;
@@ -1,23 +0,0 @@
const awaitStream = <T>(inputSteam: any, outputStream: any, allStreamsToErrorCatch: any[]) => {
return new Promise<T>((resolve, reject) => {
allStreamsToErrorCatch.forEach((currentStream: any) => {
currentStream.on("error", (e: Error) => {
reject({
message: "Await Stream Input Error",
code: 500,
error: e
})
})
})
inputSteam.pipe(outputStream).on("finish", (data: T) => {
resolve(data);
})
})
}
export default awaitStream;
@@ -1,78 +0,0 @@
import {Response, Request} from "express"
const StreamSkip = require("stream-skip");
const awaitStreamVideo = (start: number, end:number, differenceStart: number,
decipher: any, res: Response, req: Request, streamsToErrorCatch: any[], readStream: any) => {
return new Promise((resolve, reject) => {
req.on("close", () => {
// readStream.close();
decipher.destroy();
resolve();
})
req.on("end", () => {
streamsToErrorCatch.forEach((stream) => {
stream.destroy();
})
resolve();
})
streamsToErrorCatch.forEach((currentStream) => {
currentStream.on("error", (e: Error) => {
reject({
message: "Await Video Stream Input Error",
code: 500,
error: e
})
})
})
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);
}
})
}
export default awaitStreamVideo;
@@ -1,66 +0,0 @@
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;
@@ -1,33 +0,0 @@
import removeChunks from "./removeChunks";
import {Request} from "express"
const awaitUploadStream = <T>(inputSteam: any, outputStream: any, req: Request, allStreamsToErrorCatch: any[]) => {
return new Promise<T>((resolve, reject) => {
allStreamsToErrorCatch.forEach((currentStream: any) => {
currentStream.on("error", (e: Error) => {
removeChunks(outputStream);
reject({
message: "Await Stream Input Error",
code: 500,
error: e
})
})
})
req.on("aborted", () => {
removeChunks(outputStream);
})
inputSteam.pipe(outputStream).on("finish", (data: T) => {
resolve(data);
})
})
}
export default awaitUploadStream;
@@ -1,37 +0,0 @@
import s3 from "../../../db/s3";
import s3Personal from "../../../db/S3Personal";
const awaitUploadStreamS3 = (params: any, personalFile: boolean, s3Data: {id: string, key: string, bucket: string}) => {
return new Promise((resolve, reject) => {
if (personalFile) {
const s3PersonalAuth = s3Personal(s3Data.id, s3Data.key);
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();
})
}
})
}
export default awaitUploadStreamS3;
@@ -1,27 +0,0 @@
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;
@@ -1,25 +0,0 @@
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;
@@ -1,84 +0,0 @@
import mongoose from "../../../db/mongoose";
import crypto from "crypto";
import Thumbnail from "../../../models/thumbnail";
import { ObjectID } from "mongodb";
import sharp from "sharp";
import concat from "concat-stream";
import { FileInterface } from "../../../models/file";
import { UserInterface } from "../../../models/user";
const conn = mongoose.connection;
const createThumbnail = (file: FileInterface, filename: string, user: UserInterface) => {
return new Promise<FileInterface>((resolve) => {
const password = user.getEncryptionKey();
let CIPHER_KEY = crypto.createHash('sha256').update(password!).digest()
let bucket = new mongoose.mongo.GridFSBucket(conn.db, {
chunkSizeBytes: 1024 * 255
})
const readStream = bucket.openDownloadStream(new ObjectID(file._id))
readStream.on("error", (e: Error) => {
console.log("File service upload thumbnail error", e);
resolve(file);
})
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, file.metadata.IV);
decipher.on("error", (e: Error) => {
console.log("File service upload thumbnail decipher error", e);
resolve(file)
})
try {
const concatStream = concat(async(bufferData: Buffer) => {
const thumbnailIV = crypto.randomBytes(16);
const thumbnailCipher = crypto.createCipheriv("aes256", CIPHER_KEY, thumbnailIV);
bufferData = Buffer.concat([thumbnailIV, thumbnailCipher.update(bufferData), thumbnailCipher.final()]);
const thumbnailModel = new Thumbnail({name: filename, owner: user._id, data: bufferData});
await thumbnailModel.save();
const getUpdatedFile = await conn.db.collection("fs.files")
.findOneAndUpdate({"_id": new ObjectID(file._id)}, {"$set": {"metadata.hasThumbnail": true, "metadata.thumbnailID": thumbnailModel._id}})
let updatedFile: FileInterface = getUpdatedFile.value;
updatedFile = {...updatedFile, metadata: {...updatedFile.metadata, hasThumbnail: true, thumbnailID: thumbnailModel._id}} as FileInterface;
resolve(updatedFile);
}).on("error", (e: Error) => {
console.log("File service upload concat stream error", e);
resolve(file);
})
const imageResize = sharp().resize(300).on("error", (e: Error) => {
console.log("resize error", e);
resolve(file);
})
readStream.pipe(decipher).pipe(imageResize).pipe(concatStream);
} catch (e) {
console.log(e);
resolve(file);
}
})
}
export default createThumbnail;
@@ -1,81 +0,0 @@
import mongoose from "../../../db/mongoose";
import crypto from "crypto";
import Thumbnail from "../../../models/thumbnail";
import sharp from "sharp";
import {FileInterface} from "../../../models/file";
import {UserInterface} from "../../../models/user";
import fs from "fs";
import uuid from "uuid";
import env from "../../../enviroment/env";
const conn = mongoose.connection;
const createThumbnailFS = (file: FileInterface, filename: string, user: UserInterface) => {
return new Promise<FileInterface>((resolve) => {
const password = user.getEncryptionKey();
let CIPHER_KEY = crypto.createHash('sha256').update(password!).digest()
const thumbnailFilename = uuid.v4();
const readStream = fs.createReadStream(file.metadata.filePath!);
const writeStream = fs.createWriteStream(env.fsDirectory + thumbnailFilename);
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, file.metadata.IV);
readStream.on("error", (e: Error) => {
console.log("File service upload thumbnail error", e);
resolve(file);
})
writeStream.on("error", (e: Error) => {
console.log("File service upload write thumbnail error", e);
resolve(file);
})
decipher.on("error", (e: Error) => {
console.log("File service upload thumbnail decipher error", e);
resolve(file)
})
try {
const thumbnailIV = crypto.randomBytes(16);
const thumbnailCipher = crypto.createCipheriv("aes256", CIPHER_KEY, thumbnailIV);
const imageResize = sharp().resize(300).on("error", (e: Error) => {
console.log("resize error", e);
resolve(file);
})
readStream.pipe(decipher).pipe(imageResize).pipe(thumbnailCipher).pipe(writeStream);
writeStream.on("finish", async() => {
const thumbnailModel = new Thumbnail({name: filename, owner: user._id, IV: thumbnailIV, path: env.fsDirectory + thumbnailFilename});
await thumbnailModel.save();
const getUpdatedFile = await conn.db.collection("fs.files")
.findOneAndUpdate({"_id": file._id}, {"$set": {"metadata.hasThumbnail": true, "metadata.thumbnailID": thumbnailModel._id}})
let updatedFile: FileInterface = getUpdatedFile.value;
updatedFile = {...updatedFile, metadata: {...updatedFile.metadata, hasThumbnail: true, thumbnailID: thumbnailModel._id}} as FileInterface
resolve(updatedFile);
})
} catch (e) {
console.log("Thumbnail error", e);
resolve(file);
}
})
}
export default createThumbnailFS;
@@ -1,103 +0,0 @@
import mongoose from "../../../db/mongoose";
import crypto from "crypto";
import Thumbnail from "../../../models/thumbnail";
import sharp from "sharp";
import { FileInterface } from "../../../models/file";
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>( async(resolve, reject) => {
const password = user.getEncryptionKey();
let CIPHER_KEY = crypto.createHash('sha256').update(password!).digest()
const thumbnailFilename = uuid.v4();
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);
readStream.on("error", (e: Error) => {
console.log("File service upload thumbnail error", e);
resolve(file);
})
decipher.on("error", (e: Error) => {
console.log("File service upload thumbnail decipher error", e);
resolve(file)
})
try {
const thumbnailIV = crypto.randomBytes(16);
const thumbnailCipher = crypto.createCipheriv("aes256", CIPHER_KEY, thumbnailIV);
const imageResize = sharp().resize(300).on("error", (e: Error) => {
console.log("resize error", e);
resolve(file);
})
const paramsWrite: any = {
Bucket: bucket,
Body : readStream.pipe(decipher).pipe(imageResize).pipe(thumbnailCipher),
Key : thumbnailFilename
};
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, personalFile: isPersonalFile});
await thumbnailModel.save();
const getUpdatedFile = await conn.db.collection("fs.files")
.findOneAndUpdate({"_id": file._id}, {"$set": {"metadata.hasThumbnail": true, "metadata.thumbnailID": thumbnailModel._id}})
let updatedFile: FileInterface = getUpdatedFile.value;
updatedFile = {...updatedFile, metadata: {...updatedFile.metadata, hasThumbnail: true, thumbnailID: thumbnailModel._id}} as FileInterface;
resolve(updatedFile);
})
} catch (e) {
console.log("Thumbnail error", e);
resolve(file);
}
})
}
export default createThumbnailS3;
@@ -1,6 +0,0 @@
const fixEndChunkLength = (length: number) => {
return Math.floor((length-1) / 16) * 16 + 16;
}
export default fixEndChunkLength;
@@ -1,33 +0,0 @@
import { Stream } from "stream";
const getBusboyData = (busboy: any) => {
type dataType = {
file: Stream,
filename: string,
formData: Map<any, any>
}
return new Promise<dataType>((resolve, reject) => {
const formData = new Map();
busboy.on("field", (field: any, val: any) => {
formData.set(field, val)
});
busboy.on("file", async(_: string, file: Stream, filename: string) => {
resolve({
file,
filename,
formData
})
})
})
}
export default getBusboyData;
@@ -1,23 +0,0 @@
import mongoose from "../../../db/mongoose";
import { ObjectID } from "mongodb"
const conn = mongoose.connection;
const getPrevIV = (start: number, fileID: string) => {
return new Promise<Buffer | string>((resolve, reject) => {
const bucket = new mongoose.mongo.GridFSBucket(conn.db);
const stream = bucket.openDownloadStream(new ObjectID(fileID), {
start: start,
end: start + 16
});
stream.on("data", (data) => {
resolve(data);
})
})
}
export default getPrevIV;
@@ -1,39 +0,0 @@
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, isPersonal: boolean, user: UserInterface) => {
return new Promise<Buffer | string>(async(resolve, reject) => {
if (isPersonal) {
const s3Data = await user.decryptS3Data();
const params: any = {Bucket: s3Data.bucket, Key: key, Range: `bytes=${start}-${start + 15}`};
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);
})
}
})
}
export default getPrevIV;
@@ -1,27 +0,0 @@
import { GridFSBucketWriteStream } from "mongodb";
import DbUtilsFile from "../../../db/utils/fileUtils";
const dbUtilsFile = new DbUtilsFile();
const removeChunks = async(bucketStream: GridFSBucketWriteStream) => {
const uploadID = bucketStream.id as string;
try {
if (!uploadID || uploadID.length === 0) {
console.log("Invalid uploadID for remove chunks");
return;
}
await dbUtilsFile.removeChunksByID(uploadID);
} catch(e) {
console.log("Could not remove chunks for canceled upload", uploadID, e);
}
}
export default removeChunks;
@@ -1,20 +0,0 @@
import fs from "fs";
const removeChunksFS = (path: string) => {
return new Promise((resolve, reject) => {
fs.unlink(path, (err) => {
if (err) {
console.log("Could not remove fs file", err);
resolve();
}
resolve();
})
})
}
export default removeChunksFS;
module.exports = removeChunksFS;

Some files were not shown because too many files have changed in this diff Show More