UNPKG

ali-flmngr-server-fixed

Version:

> Node.js Backend for Flmngr file manager

469 lines (452 loc) 23.2 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const Message_1 = require("../models/Message"); const utils_1 = require("../utils"); const { nanoid } = require('nanoid'); const { readdirSync, renameSync } = require("fs"); const mmm = require('mmmagic'); const magic = new mmm.Magic(mmm.MAGIC_MIME_TYPE); class FMController { constructor(_fmRepository, _rootDirPath) { this._fmRepository = _fmRepository; this._rootDirPath = _rootDirPath; this._cacheDirName = 'cache'; this._checkPathStartsWithRoot = (pathTo) => pathTo.startsWith(this._rootDirPath); this._toAbsolutePath = (dirPath) => path_1.default.join(this._rootDirPath, ...path_1.default .join(...dirPath.split('/')) .split(path_1.default.sep) .slice(1)); this._sendError = (res, code, args = null) => { res.json({ data: null, error: { args, code, files: null, }, }); }; this.getVersion = (_, res) => __awaiter(this, void 0, void 0, function* () { res.json({ error: null, data: { version: 1, language: 'typescript' } }); }); this.dirList = (_, res) => __awaiter(this, void 0, void 0, function* () { let isDirExists = fs_1.default.existsSync(this._rootDirPath) && fs_1.default.lstatSync(this._rootDirPath).isDirectory(); if (!isDirExists) { return this._sendError(res, Message_1.FMErrorMessage.ROOT_DIR_DOES_NOT_EXIST); } const dirList = yield this._fmRepository.getDirectories(this._rootDirPath); const pathToCut = path_1.default.dirname(this._rootDirPath); const data = (yield Promise.all(dirList.map((dirPath) => __awaiter(this, void 0, void 0, function* () { if (dirPath.includes(path_1.default.join(this._rootDirPath, this._cacheDirName)) || dirPath.includes(path_1.default.join(this._rootDirPath, 'tmp'))) { return; } return { f: yield this._fmRepository.countFiles(dirPath), d: yield this._fmRepository.countDirectories(dirPath), p: dirPath .replace(pathToCut, '') .split(path_1.default.sep) .join('/'), }; })))).filter((item) => Boolean(item)); // Для фильтрации вырезанных папок res.json({ error: null, data }); }); this.dirCreate = (req, res) => __awaiter(this, void 0, void 0, function* () { const { d: dirPath, n: name } = req.body; if (utils_1.areThereForbiddenCharacters(name)) { return this._sendError(res, Message_1.FMErrorMessage.DIR_NAME_CONTAINS_INVALID_SYMBOLS); } const absPath = this._toAbsolutePath(dirPath); if (!this._checkPathStartsWithRoot(absPath)) { return this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_CREATE_DIRECTORY); } try { yield this._fmRepository.createDirectory(absPath, name); res.json({ data: true, error: null }); } catch (error) { this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_CREATE_DIRECTORY); } }); this.dirRename = (req, res) => __awaiter(this, void 0, void 0, function* () { const { d: dirPath, n: name } = req.body; if (utils_1.areThereForbiddenCharacters(name)) { return this._sendError(res, Message_1.FMErrorMessage.DIR_NAME_CONTAINS_INVALID_SYMBOLS); } const absPath = this._toAbsolutePath(dirPath); if (!this._checkPathStartsWithRoot(absPath)) { return this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_CREATE_DIRECTORY); } try { yield this._fmRepository.renameDirectory(absPath, name); res.json({ data: true, error: null }); } catch (error) { if (['ENOTEMPTY', 'EEXIST', 'EPERM', 'EACCES'].includes(error.code)) { return this._sendError(res, Message_1.FMErrorMessage.FILE_ALREADY_EXISTS, [name]); } this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_RENAME); } }); this.dirDelete = (req, res) => __awaiter(this, void 0, void 0, function* () { const { d: dirPath } = req.body; const absPath = this._toAbsolutePath(dirPath); if (absPath === this._rootDirPath || !this._checkPathStartsWithRoot(absPath)) { return this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_DELETE_DIRECTORY); } try { yield this._fmRepository.removeDirectory(absPath); res.json({ data: true, error: null }); } catch (error) { this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_DELETE_DIRECTORY); } }); this.dirCopy = (req, res) => __awaiter(this, void 0, void 0, function* () { const { d: dirPath, n: newPath } = req.body; const absDirPath = this._toAbsolutePath(dirPath); const absNewPath = this._toAbsolutePath(newPath); if (!this._checkPathStartsWithRoot(absDirPath) || !this._checkPathStartsWithRoot(absNewPath)) { return this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_MOVING_FILES); } try { yield this._fmRepository.copyDirectory(absDirPath, path_1.default.join(absNewPath, utils_1.getTitle(dirPath))); res.json({ data: true, error: null }); } catch (error) { this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_COPYING_FILES); } }); this.dirMove = (req, res) => __awaiter(this, void 0, void 0, function* () { const { d: dirPath, n: newPath } = req.body; const absDirPath = this._toAbsolutePath(dirPath); const absNewPath = this._toAbsolutePath(newPath); if (!this._checkPathStartsWithRoot(absDirPath) || !this._checkPathStartsWithRoot(absNewPath)) { return this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_MOVING_FILES); } try { yield this._fmRepository.moveDirectory(absDirPath, path_1.default.join(absNewPath, utils_1.getTitle(dirPath))); res.json({ data: true, error: null }); } catch (error) { this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_MOVING_FILES); } }); this.dirDownload = (req, res) => __awaiter(this, void 0, void 0, function* () { let { d: dirPath } = req.query; const dirAbsolutePath = this._toAbsolutePath(dirPath); if (!this._fmRepository.isDirectoryOrFileExists(dirAbsolutePath) || !this._checkPathStartsWithRoot(dirAbsolutePath)) { res.sendStatus(404); return; } if (typeof (dirPath) != "string") { dirPath = '0'; } res.attachment(`${utils_1.getTitle(dirPath)}.zip`); try { yield this._fmRepository.downloadDirectory(dirAbsolutePath, res); } catch (e) { res.sendStatus(500); } }); this.fileListPaged = (req, res) => __awaiter(this, void 0, void 0, function* () { const { dir: dirPath } = req.body; const absDirPath = this._toAbsolutePath(dirPath); if (!this._checkPathStartsWithRoot(absDirPath)) { return this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_CREATE_DIRECTORY); } if (!(yield this._fmRepository.isDirectoryOrFileExists(absDirPath))) { return this._sendError(res, Message_1.FMErrorMessage.DIR_DOES_NOT_EXIST, [dirPath]); } try { const fileListPaged = yield this._fmRepository.getFiles(absDirPath); const files = yield Promise.all(fileListPaged.map((filePath) => __awaiter(this, void 0, void 0, function* () { return ({ name: yield this._fmRepository.getName(filePath), size: yield this._fmRepository.getFileSize(filePath), timestamp: yield this._fmRepository.getFileCreationTime(filePath), width: yield this._fmRepository.getFileWidth(filePath), height: yield this._fmRepository.getFileHeight(filePath), blurHash: yield this._fmRepository.getFileBlurHash(filePath), formats: [], }); }))); let data = { files, isEnd: true }; res.json({ error: null, data: data }); } catch (error) { return this._sendError(res, Message_1.FMErrorMessage.DIR_CANNOT_BE_READ); } }); this.fileDelete = (req, res) => __awaiter(this, void 0, void 0, function* () { const { fs: filePaths } = req.body; const filePathsList = filePaths.split('|'); if (filePathsList.some((filePath) => { const absPath = this._toAbsolutePath(filePath); return !this._fmRepository.isDirectoryOrFileExists(absPath) || !this._checkPathStartsWithRoot(absPath); })) { return this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_DELETE_FILE, filePathsList.map(utils_1.getLastDir)); } try { yield Promise.all(filePathsList.map((filePath) => { this._fmRepository.removeFile(this._toAbsolutePath(filePath)); })); res.json({ data: true, error: null }); } catch (error) { this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_DELETE_FILE); } }); this.fileCopy = (req, res) => __awaiter(this, void 0, void 0, function* () { const { fs: filePaths, n: newPath } = req.body; const filePathsList = filePaths.split('|'); if (filePathsList.some((filePath) => { const absPath = this._toAbsolutePath(filePath); return !this._fmRepository.isDirectoryOrFileExists(absPath) || !this._checkPathStartsWithRoot(absPath); })) { return this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_COPYING_FILES); } const absNewPath = this._toAbsolutePath(newPath); if (!this._checkPathStartsWithRoot(absNewPath)) { return this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_COPYING_FILES); } try { yield Promise.all(filePaths.split('|').map((filePath) => (this._fmRepository.copyFile(this._toAbsolutePath(filePath), path_1.default.join(absNewPath, utils_1.getLastDir(filePath)))))); res.json({ data: true, error: null }); } catch (error) { this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_COPYING_FILES); } }); this.fileRename = (req, res) => __awaiter(this, void 0, void 0, function* () { const { f: filePath, n: name } = req.body; if (utils_1.areThereForbiddenCharacters(utils_1.getFileNameWithoutExt(name))) { return this._sendError(res, Message_1.FMErrorMessage.DIR_NAME_CONTAINS_INVALID_SYMBOLS); } if (utils_1.getFileNameWithoutExt(name) === '') { return this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_RENAME); } const absFilePath = this._toAbsolutePath(filePath); if ((yield this._fmRepository.isDirectoryOrFileExists(utils_1.getPathWithNewName(absFilePath, name))) || !this._checkPathStartsWithRoot(absFilePath)) { return this._sendError(res, Message_1.FMErrorMessage.FILE_ALREADY_EXISTS, [name]); } try { yield this._fmRepository.renameFile(absFilePath, name); res.json({ data: true, error: null }); } catch (error) { this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_RENAME); } }); this.fileMove = (req, res) => __awaiter(this, void 0, void 0, function* () { const { fs: filePaths, n: newPath } = req.body; const filePathsList = filePaths.split('|'); const absNewPath = this._toAbsolutePath(newPath); if (!this._checkPathStartsWithRoot(absNewPath)) { return this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_MOVING_FILES); } if (filePathsList.some((filePath) => { const absPath = this._toAbsolutePath(filePath); return !this._fmRepository.isDirectoryOrFileExists(absPath) || !this._checkPathStartsWithRoot(absPath); })) { return this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_MOVING_FILES); } try { yield Promise.all(filePathsList.map((filePath) => { this._fmRepository.moveFile(this._toAbsolutePath(filePath), path_1.default.join(this._toAbsolutePath(newPath), utils_1.getLastDir(filePath))); })); res.json({ data: true, error: null }); } catch (error) { this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_MOVING_FILES); } }); this.fileOriginal = (req, res) => __awaiter(this, void 0, void 0, function* () { let { f: filePath } = req.body; const fileAbsolutePath = this._toAbsolutePath(filePath); if (!this._fmRepository.isDirectoryOrFileExists(fileAbsolutePath) || !this._checkPathStartsWithRoot(fileAbsolutePath)) { res.sendStatus(404); return; } try { if (typeof (filePath) != "string") { filePath = '0'; } const ext = path_1.default.extname(filePath); if (ext !== '.gif' && ext !== '.PNG' && ext !== '.png' && ext !== '.jpg' && ext !== '.jpeg' && ext !== '.webp' && ext !== '.JPG' && ext !== '.JPEG') { res.sendStatus(415); return; } res.setHeader('Content-Type', `image/${ext.replace('.', '')}`); res.setHeader('Content-Length', yield this._fmRepository.getFileSize(fileAbsolutePath)); res.send(yield this._fmRepository.getImageOriginal(fileAbsolutePath)); } catch (error) { res.sendStatus(500); } }); this.filePreview = (req, res) => __awaiter(this, void 0, void 0, function* () { let { f: filePath, width: width } = req.body; let name = yield this._fmRepository.getName(filePath); let LengthOfName = (name.length + 1) * -1; let filedir = String(filePath).slice(0, LengthOfName); const fileAbsolutePath = this._toAbsolutePath(filedir); if (!this._fmRepository.isDirectoryOrFileExists(fileAbsolutePath) || !this._checkPathStartsWithRoot(fileAbsolutePath)) { res.sendStatus(404); return; } try { if (!this._fmRepository.isDirectoryOrFileExists(fileAbsolutePath)) { res.sendStatus(404); return; } if (typeof (filePath) != "string") { filePath = '0'; } const ext = path_1.default.extname(filePath); if (ext !== '.gif' && ext !== '.PNG' && ext !== '.png' && ext !== '.jpg' && ext !== '.jpeg' && ext !== '.webp' && ext !== '.JPG' && ext !== '.JPEG') { res.sendStatus(415); return; } if (typeof (width) != "string") { width = '0'; } res.setHeader('Content-Type', `image/${ext.replace('.', '')}`); res.setHeader('Content-Length', yield this._fmRepository.getFileSize(fileAbsolutePath)); res.send(yield this._fmRepository.getImagePreview(name, fileAbsolutePath, parseInt(width), path_1.default.join(this._rootDirPath, this._cacheDirName))); } catch (error) { res.sendStatus(500); } }); this.fileUpload = (req, res) => __awaiter(this, void 0, void 0, function* () { let { data } = req.body data = JSON.parse(data); const { action, uplaodId } = data; if (action == 'uploadInit') { return res.send({ "uploadId": nanoid(10), "settings": { "maxImageResizeWidth": 5000, "maxImageResizeHeight": 5000 }, "ok": true }); } if (action === 'uploadAddFile') { const imageMimeTypes = ["image/tiff", "image/svg+xml", "image/png", "image/jpeg", "image/vnd.microsoft.icon", "image/gif", "image/bmp", "image/webp"]; const isImage = imageMimeTypes.includes(req.file.mimetype); let width = null, height = null; if (isImage) { width = yield this._fmRepository.getFileWidth(req.file.path); height = yield this._fmRepository.getFileHeight(req.file.path); } return res.send({ file: { "isCommited": false, "name": req.file.filename, "dir": `${uplaodId}/`, "bytes": req.file.size, isImage, width, height, "errors": [], "sizes": [] }, ok: true }); } if (action == 'uploadCommit') { let { dir } = data; const folderPath = path_1.default.resolve(this._rootDirPath, '../tempFile'); const files = [], files2 = []; // make response obj for (const file of readdirSync(folderPath)) { const filePath = `${folderPath}/${file}`; const { isImage, width, height } = this.isFileImage(filePath, yield this.getFileMimeType(filePath)); const fileSize = yield this._fmRepository.getFileSize(filePath); let name = file; dir = `/${dir}/`; let destPath = this._rootDirPath + dir + name; if(fs_1.default.existsSync(destPath)) { name = `${Date.now()}-${file}`; destPath = this._rootDirPath + dir + name; } fs_1.default.renameSync(filePath, destPath); files.push({ isCommited: true, name, dir, bytes: fileSize, isImage, width, height, errors: [], sizes: [] }); files2.push({ name, size: fileSize, timestamp: Date.now(), width, height, blurHash: null, formats: [] }); } res.send({ files, files2, ok: true, }); } }); this.isFileImage = (filePath, mimytype) => __awaiter(this, void 0, void 0, function* () { const imageMimeTypes = ["image/tiff", "image/svg+xml", "image/png", "image/jpeg", "image/vnd.microsoft.icon", "image/gif", "image/bmp", "image/webp"]; return { isImage: imageMimeTypes.includes(mimytype), width: yield this._fmRepository.getFileWidth(filePath), height: yield this._fmRepository.getFileHeight(filePath) } }); this.fileListSpecified = (req, res) => __awaiter(this, void 0, void 0, function* () { let response = { "error": null, "data": [] }; return res.json(response); }); this.getFileMimeType = (filePath) => __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { magic.detectFile(filePath, (error, result) => { if (error) return reject(error); resolve(result); }); }); }); } } exports.default = FMController; //# sourceMappingURL=FMController.js.map