started better error handling and validation

This commit is contained in:
subnub
2024-09-28 08:24:35 -04:00
parent af727291d0
commit 5f443a7101
20 changed files with 215 additions and 65 deletions
+12 -5
View File
@@ -235,12 +235,15 @@ class FileController {
handleFinish(filename, metadata);
});
} catch (e: unknown) {
if (e instanceof Error) {
console.log("\nUploading File Error File Route:", e.message);
}
if (!responseSent) {
res.writeHead(500, { Connection: "close" });
res.end();
if (e instanceof Error) {
console.log("\nUploading File Error File Route:", e.message);
res.end(e.message);
} else {
console.log("\nUploading File Error File Route:", e);
res.end("Server error uploading file");
}
}
}
};
@@ -510,6 +513,10 @@ class FileController {
const accessTokenStreamVideo = req.accessTokenStreamVideo!;
if (!accessTokenStreamVideo) {
throw new NotAuthorizedError("No Access Token");
}
await User.updateOne(
{ _id: userID },
{ $pull: { tempTokens: { token: accessTokenStreamVideo } } }
@@ -674,7 +681,7 @@ class FileController {
try {
const userID = req.user._id;
let searchQuery = req.query.search || "";
const searchQuery = req.query.search as string;
const trashMode = req.query.trashMode === "true";
const mediaMode = req.query.mediaMode === "true";
+13 -4
View File
@@ -118,11 +118,20 @@ class DbUtil {
const queryObj = createQuery(queryData);
const fileList = await File.find(queryObj)
.sort(formattedSortBy)
.limit(limit);
if (sortBy.includes("alp_")) {
const fileList = await File.find(queryObj)
.collation({ locale: "en", strength: 2 })
.sort(formattedSortBy)
.limit(limit);
return fileList;
return fileList;
} else {
const fileList = await File.find(queryObj)
.sort(formattedSortBy)
.limit(limit);
return fileList;
}
};
removeTempToken = async (user: UserInterface, tempToken: string) => {
+2
View File
@@ -8,6 +8,7 @@ import {
getListValidationRules,
getPublicDownloadValidationRules,
getQuickListValidationRules,
getSuggestedListValidationRules,
getThumbnailValidationRules,
} from "../middleware/files/files-middleware";
@@ -91,6 +92,7 @@ router.get(
router.get(
"/file-service/suggested-list",
auth,
getSuggestedListValidationRules,
fileController.getSuggestedList
);
@@ -51,3 +51,20 @@ export const moveFileValidationRules = [
query("parentID").isString().withMessage("Parent 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,
];
+66
View File
@@ -86,6 +86,72 @@ export interface FileInterface
metadata: FileMetadateInterface;
}
fileSchema.index(
{ "metadata.owner": 1, "metadata.parent": 1, filename: 1 },
{ background: true }
);
fileSchema.index(
{ "metadata.owner": 1, "metadata.parent": 1, uploadDate: 1 },
{ background: true }
);
fileSchema.index(
{ "metadata.owner": 1, "metadata.parent": 1, filename: 1 },
{ background: true }
);
fileSchema.index(
{ "metadata.owner": 1, "metadata.parent": 1, uploadDate: 1 },
{ collation: { locale: "en", strength: 2 }, background: true }
);
fileSchema.index(
{ "metadata.owner": 1, "metadata.parent": 1, filename: 1 },
{ collation: { locale: "en", strength: 2 }, background: true }
);
fileSchema.index({ "metadata.owner": 1 }, { background: true });
fileSchema.index({ "metadata.parent": 1 }, { background: true });
fileSchema.index({ uploadDate: 1 }, { background: true });
fileSchema.index({ "metadata.trashed": 1 }, { background: true });
fileSchema.index({ "metadata.hasThumbnail": 1 }, { background: true });
fileSchema.index(
{ filename: 1 },
{ collation: { locale: "en", strength: 2 }, background: true }
);
fileSchema.index(
{ "metadata.parent": 1 },
{ collation: { locale: "en", strength: 2 }, background: true }
);
fileSchema.index(
{ "metadata.owner": 1 },
{ collation: { locale: "en", strength: 2 }, background: true }
);
// fileSchema.index(
// { filename: 1 },
// { collation: { locale: "en", strength: 2 }, background: true }
// );
// fileSchema.index(
// { filename: -1 },
// { collation: { locale: "en", strength: 2 }, background: true }
// );
// fileSchema.index({ uploadDate: 1 }, { background: true });
// fileSchema.index({ uploadDate: -1 }, { background: true });
// fileSchema.index({ "metadata.parent": 1 }, { background: true });
// fileSchema.index({ "metadata.owner": 1 }, { background: true });
// fileSchema.index({ "metadata.isVideo": 1 }, { background: true });
// fileSchema.index({ "metadata.hasThumbnail": 1 }, { background: true });
// fileSchema.index({ "metadata.trashed": 1 }, { background: true });
const File = mongoose.model<FileInterface>("fs.files", fileSchema);
export default File;
+8
View File
@@ -42,6 +42,14 @@ export interface FolderInterface
trashed: boolean | null;
}
folderSchema.index({ owner: 1, parent: 1, name: 1 }, { background: true });
folderSchema.index({ owner: 1, parent: 1, createdAt: 1 }, { background: true });
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;
+2
View File
@@ -42,6 +42,8 @@ export interface ThumbnailInterface extends Document {
updatedAt: Date;
}
thumbnailSchema.index({ owner: 1 });
const Thumbnail = mongoose.model<ThumbnailInterface>(
"Thumbnail",
thumbnailSchema
+1 -1
View File
@@ -36,7 +36,7 @@ if (process.env.SSL === "true") {
server = http.createServer(app);
require("../db/mongoose");
require("../db/connections/mongoose");
app.use(cookieParser(env.passwordCookie));
app.use(helmet());
@@ -6,7 +6,10 @@ import crypto from "crypto";
import getBusboyData from "./utils/getBusboyData";
import videoChecker from "../../utils/videoChecker";
import uuid from "uuid";
import File, { FileInterface } from "../../models/file-model";
import File, {
FileInterface,
FileMetadateInterface,
} from "../../models/file-model";
import FileDB from "../../db/mongoDB/fileDB";
import FolderDB from "../../db/mongoDB/folderDB";
import Thumbnail, { ThumbnailInterface } from "../../models/thumbnail-model";
@@ -19,6 +22,8 @@ import { ObjectId } from "mongodb";
import { S3Actions } from "./actions/S3-actions";
import { FilesystemActions } from "./actions/file-system-actions";
import { createGenericParams } from "./utils/storageHelper";
import { check } from "express-validator";
import { Readable } from "stream";
const fileDB = new FileDB();
const folderDB = new FolderDB();
@@ -44,11 +49,39 @@ class StorageService {
const filename = fileInfo.filename;
const parent = formData.get("parent") || "/";
const size = formData.get("size") || "";
let hasThumbnail = false;
let thumbnailID = "";
const size = +formData.get("size");
const hasThumbnail = false;
const thumbnailID = "";
const isVideo = videoChecker(filename);
const errors = [];
if (!filename || filename.length === 0 || filename.length > 255) {
errors.push({
msg: "Filename is required and length must be greater than 0 and less than 255",
param: "filename",
});
}
if (!file) {
errors.push({ msg: "File is required", param: "file" });
}
// @prettier-ignore
if (!(file instanceof Readable)) {
errors.push({ msg: "File must be a readable stream", param: "file" });
}
if (!size || size < 0) {
errors.push({ msg: "Size must be a positive integer", param: "size" });
}
if (errors.length > 0) {
throw new Error(
`Invalid request parameters ${errors.map((e) => e.msg).join(", ")}`
);
}
const parentList = [];
if (parent !== "/") {
@@ -65,7 +98,7 @@ class StorageService {
const randomFilenameID = uuid.v4();
const metadata = {
owner: user._id,
owner: user._id.toString(),
parent,
parentList: parentList.toString(),
hasThumbnail,
@@ -73,7 +106,7 @@ class StorageService {
isVideo,
size,
IV: initVect,
} as any;
} as FileMetadateInterface;
if (env.dbType === "fs") {
metadata.filePath = env.fsDirectory + randomFilenameID;
+8 -7
View File
@@ -1,12 +1,13 @@
class ForbiddenError extends Error {
code: number;
isCustomError: boolean;
code: number;
constructor(args: any) {
super(args);
constructor(args: any) {
super(args);
this.code = 403;
}
this.code = 403;
this.isCustomError = true;
}
}
export default ForbiddenError;
export default ForbiddenError;
+8 -7
View File
@@ -1,12 +1,13 @@
class InternalServerError extends Error {
code: number;
isCustomError: boolean;
code: number;
constructor(args: any) {
super(args);
constructor(args: any) {
super(args);
this.code = 500;
}
this.code = 500;
this.isCustomError = true;
}
}
export default InternalServerError;
export default InternalServerError;
+8 -7
View File
@@ -1,12 +1,13 @@
class NotAuthorizedError extends Error {
code: number;
isCustomError: boolean;
code: number;
constructor(args: any) {
super(args);
constructor(args: any) {
super(args);
this.code = 401;
}
this.code = 401;
this.isCustomError = true;
}
}
export default NotAuthorizedError;
export default NotAuthorizedError;
+8 -7
View File
@@ -1,12 +1,13 @@
class NotEmailVerifiedError extends Error {
code: number;
isCustomError: boolean;
code: number;
constructor(args: any) {
super(args);
constructor(args: any) {
super(args);
this.code = 404;
}
this.code = 404;
this.isCustomError = true;
}
}
export default NotEmailVerifiedError;
export default NotEmailVerifiedError;
+8 -7
View File
@@ -1,12 +1,13 @@
class NotFoundError extends Error {
code: number;
isCustomError: boolean;
code: number;
constructor(args: any) {
super(args);
constructor(args: any) {
super(args);
this.code = 404;
}
this.code = 404;
this.isCustomError = true;
}
}
export default NotFoundError;
export default NotFoundError;
+8 -7
View File
@@ -1,12 +1,13 @@
class NotValidDataError extends Error {
code: number;
isCustomError: boolean;
code: number;
constructor(args: any) {
super(args);
constructor(args: any) {
super(args);
this.code = 403;
}
this.code = 403;
this.isCustomError = true;
}
}
export default NotValidDataError;
export default NotValidDataError;
+1 -1
View File
@@ -2,5 +2,5 @@
"watch": ["dist/"],
"ignore": ["src", "node_modules"],
"ext": "js,json",
"exec": "node dist/server/serverStart.js"
"exec": "node dist/server/server-start.js"
}
+2 -2
View File
@@ -19,7 +19,7 @@
"test": "NODE_ENV=test env-cmd -f ./config/test.env jest --config=jest.config.json --runInBand",
"start:dev": "NODE_ENV=development node dist/server/serverStart.js",
"start:debug": "NODE_ENV=development node --inspect dist/server/serverStart.js",
"start": "cross-env NODE_ENV=production node dist/server/serverStart.js",
"start": "cross-env NODE_ENV=production node dist/server/server-start.js",
"create-indexes-database": "node serverUtils/createIndexes.js",
"increase-node-memory": "export NODE_OPTIONS=--max_old_space_size=8000",
"create-indexes-database:dev": "node serverUtils/createIndexes.js",
@@ -34,7 +34,7 @@
"vite-test": "vite",
"dev-test": "concurrently \"vite\" \"nodemon server.js\"",
"dev-hot": "concurrently \"vite\" \"tsc -w -p ./backend/tsconfig.json\" \"npm run dev:backend\"",
"dev:backend": "nodemon dist/server/serverStart.js",
"dev:backend": "nodemon dist/server/server-start.js",
"vite-build": "vite build",
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'"
},
+2 -2
View File
@@ -42,7 +42,7 @@ const PublicDownloadPage = () => {
return (
<div className="w-screen h-screen flex justify-center items-center">
<Spinner />
<ToastContainer position="bottom-right" />
<ToastContainer position="bottom-left" />
</div>
);
}
@@ -121,7 +121,7 @@ const PublicDownloadPage = () => {
</div>
</div>
</div>
<ToastContainer position="bottom-right" />
<ToastContainer position="bottom-left" />
</div>
);
};
+1 -1
View File
@@ -19,7 +19,7 @@ const Homepage = () => {
</div>
</div>
<ToastContainer position="bottom-right" />
<ToastContainer position="bottom-left" />
</div>
);
};
+1 -1
View File
@@ -249,7 +249,7 @@ const LoginPage = () => {
</form>
</div>
</div>
<ToastContainer position="bottom-right" />
<ToastContainer position="bottom-left" />
</div>
);
};