@@ -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
@@ -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"]
|
||||
@@ -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"]
|
||||
@@ -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"]
|
||||
@@ -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=
|
||||
@@ -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=
|
||||
@@ -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=
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
@@ -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",
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
@@ -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 };
|
||||
|
||||
@@ -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;
|
||||
@@ -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
Reference in New Issue
Block a user