@restroom-mw/files
Advanced tools
Comparing version 0.13.1-b58baa9.9 to 0.13.1-b59dc98.65
export declare const DOWNLOAD = "download the {} and extract it into {}"; | ||
export declare const STORE_RESULT = "store {} in the file {}"; | ||
export declare const READ = "read the content of {}"; | ||
//# sourceMappingURL=actions.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.STORE_RESULT = exports.DOWNLOAD = void 0; | ||
exports.READ = exports.STORE_RESULT = exports.DOWNLOAD = void 0; | ||
exports.DOWNLOAD = "download the {} and extract it into {}"; | ||
exports.STORE_RESULT = "store {} in the file {}"; | ||
exports.READ = "read the content of {}"; |
import { NextFunction, Request, Response } from "express"; | ||
/** | ||
* Base dir to store data for the user | ||
* @constant | ||
* @type {string} | ||
*/ | ||
export declare const FILES_DIR: string; | ||
declare const _default: (req: Request, res: Response, next: NextFunction) => void; | ||
export default _default; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -15,8 +15,10 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.FILES_DIR = void 0; | ||
const core_1 = require("@restroom-mw/core"); | ||
const utils_1 = require("@restroom-mw/utils"); | ||
const axios_1 = __importDefault(require("axios")); | ||
const fs_1 = __importDefault(require("fs")); | ||
const os_1 = __importDefault(require("os")); | ||
const extract_zip_1 = __importDefault(require("extract-zip")); | ||
const path_1 = __importDefault(require("path")); | ||
require("dotenv").config(); | ||
/** | ||
@@ -36,11 +38,19 @@ * `download the 'myUrl' and extract it into 'myFolder'` | ||
const actions_2 = require("./actions"); | ||
const actions_3 = require("./actions"); | ||
/** | ||
* Base dir to store data for the user | ||
* @constant | ||
* @type {string} | ||
*/ | ||
exports.FILES_DIR = process.env.FILES_DIR; | ||
let input = {}; | ||
// save path must be subdirs of FILES_DIR | ||
const validatePath = (p) => { | ||
if (!utils_1.FILES_DIR) | ||
if (!exports.FILES_DIR) | ||
throw new Error(`FILES_DIR is not defined`); | ||
if (utils_1.FILES_DIR != "/") { | ||
const relative = path_1.default.relative(utils_1.FILES_DIR, p); | ||
if (exports.FILES_DIR != "/") { | ||
const relative = path_1.default.relative(exports.FILES_DIR, p); | ||
const isSubdir = relative && !relative.startsWith('..') && !path_1.default.isAbsolute(relative); | ||
if (!isSubdir) { | ||
throw new Error(`Result path outside ${utils_1.FILES_DIR}`); | ||
throw new Error(`Result path outside ${exports.FILES_DIR}`); | ||
} | ||
@@ -51,2 +61,20 @@ } | ||
const rr = new core_1.Restroom(req, res); | ||
rr.onBefore((params) => __awaiter(void 0, void 0, void 0, function* () { | ||
const { zencode, keys, data } = params; | ||
if (zencode.match(actions_3.READ)) { | ||
const params = zencode.paramsOf(actions_3.READ); | ||
for (const file of params) { | ||
validatePath(file); | ||
const absoluteFile = path_1.default.join(exports.FILES_DIR, file); | ||
try { | ||
const content = fs_1.default.readFileSync(absoluteFile, 'utf8'); | ||
Object.assign(data, JSON.parse(content)); | ||
} | ||
catch (e) { | ||
throw new Error(`[FILES] error while reading the file ${absoluteFile}`); | ||
} | ||
} | ||
} | ||
input = rr.combineDataKeys(data, keys); | ||
})); | ||
rr.onSuccess((params) => __awaiter(void 0, void 0, void 0, function* () { | ||
@@ -57,26 +85,29 @@ const { result, zencode } = params; | ||
for (let i = 0; i < allPassOutputs.length; i += 2) { | ||
const file = result[allPassOutputs[i]]; | ||
const folder = result[allPassOutputs[i + 1]]; | ||
if (file && folder) { | ||
try { | ||
const absoluteFolder = path_1.default.resolve(utils_1.FILES_DIR + "/" + folder); | ||
validatePath(absoluteFolder); | ||
const response = yield axios_1.default.get(file, { | ||
responseType: 'arraybuffer' | ||
}); | ||
const tempdir = fs_1.default.mkdtempSync("/tmp/restroom"); | ||
const tempfile = tempdir + "/downloaded"; | ||
fs_1.default.writeFileSync(tempfile, response.data); | ||
yield (0, extract_zip_1.default)(tempfile, { dir: absoluteFolder }); | ||
fs_1.default.unlinkSync(tempfile); | ||
fs_1.default.rmdirSync(tempdir); | ||
} | ||
catch (e) { | ||
next(e); | ||
throw new Error(`[FILES] Error sending the result to "${file}": ${e}`); | ||
} | ||
const file = result[allPassOutputs[i]] || | ||
input[allPassOutputs[i]]; | ||
const folder = result[allPassOutputs[i + 1]] || | ||
input[allPassOutputs[i + 1]]; | ||
if (!file) { | ||
throw new Error(`[FILES] url not defined`); | ||
} | ||
else { | ||
throw new Error(`[FILES] url or destination folder not defined`); | ||
if (!folder) { | ||
throw new Error(`[FILES] destination folder not defined ${Object.keys(input)}`); | ||
} | ||
try { | ||
const absoluteFolder = path_1.default.resolve(path_1.default.join(exports.FILES_DIR, folder)); | ||
validatePath(absoluteFolder); | ||
const response = yield axios_1.default.get(file, { | ||
responseType: 'arraybuffer' | ||
}); | ||
const tempdir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'restroom-')); | ||
const tempfile = path_1.default.join(tempdir, "downloaded"); | ||
fs_1.default.writeFileSync(tempfile, response.data); | ||
yield (0, extract_zip_1.default)(tempfile, { dir: absoluteFolder }); | ||
fs_1.default.unlinkSync(tempfile); | ||
fs_1.default.rmdirSync(tempdir); | ||
} | ||
catch (e) { | ||
next(e); | ||
throw new Error(`[FILES] Error sending the result to "${file}": ${e}`); | ||
} | ||
} | ||
@@ -87,21 +118,24 @@ } | ||
for (let i = 0; i < allPassOutputs.length; i += 2) { | ||
const variable = result[allPassOutputs[i]]; | ||
const file = result[allPassOutputs[i + 1]]; | ||
if (variable && file) { | ||
const variableJson = JSON.stringify(variable); | ||
try { | ||
const absoluteFile = path_1.default.resolve(utils_1.FILES_DIR + "/" + file); | ||
validatePath(absoluteFile); | ||
const absoluteFolder = path_1.default.dirname(absoluteFile); | ||
fs_1.default.mkdirSync(absoluteFolder, { recursive: true }); | ||
fs_1.default.writeFileSync(absoluteFile, variableJson); | ||
} | ||
catch (e) { | ||
next(e); | ||
throw new Error(`[FILES] Error saving the result to "${file}": ${e}`); | ||
} | ||
const variable = result[allPassOutputs[i]] || | ||
input[allPassOutputs[i]]; | ||
const file = result[allPassOutputs[i + 1]] || | ||
input[allPassOutputs[i + 1]]; | ||
if (!variable) { | ||
throw new Error(`[FILES] variable not defined`); | ||
} | ||
else { | ||
throw new Error(`[FILES] variable or destination folder not defined`); | ||
if (!file) { | ||
throw new Error(`[FILES] destination file not defined`); | ||
} | ||
const variableJson = JSON.stringify(variable); | ||
try { | ||
const absoluteFile = path_1.default.resolve(path_1.default.join(exports.FILES_DIR, file)); | ||
validatePath(absoluteFile); | ||
const absoluteFolder = path_1.default.dirname(absoluteFile); | ||
fs_1.default.mkdirSync(absoluteFolder, { recursive: true }); | ||
fs_1.default.writeFileSync(absoluteFile, variableJson); | ||
} | ||
catch (e) { | ||
next(e); | ||
throw new Error(`[FILES] Error saving the result to "${file}": ${e}`); | ||
} | ||
} | ||
@@ -108,0 +142,0 @@ } |
{ | ||
"name": "@restroom-mw/files", | ||
"version": "0.13.1-b58baa9.9+b58baa9", | ||
"version": "0.13.1-b59dc98.65+b59dc98", | ||
"description": "Utilities middleware to work with files for Restroom", | ||
@@ -35,3 +35,3 @@ "author": "Alberto Lerda <alberto@dyne.org>", | ||
}, | ||
"gitHead": "b58baa9af523ea2554745c95bb088aa6f214caa4" | ||
"gitHead": "b59dc989cf031c4ce5b6751a6d6713bf57b6e826" | ||
} |
@@ -1,2 +0,3 @@ | ||
export const DOWNLOAD= "download the {} and extract it into {}"; | ||
export const STORE_RESULT= "store {} in the file {}"; | ||
export const DOWNLOAD = "download the {} and extract it into {}"; | ||
export const STORE_RESULT = "store {} in the file {}"; | ||
export const READ = "read the content of {}"; |
122
src/index.ts
import {Restroom} from "@restroom-mw/core"; | ||
import {FILES_DIR} from "@restroom-mw/utils"; | ||
import axios from "axios"; | ||
import {NextFunction, Request, Response} from "express"; | ||
import fs from 'fs' | ||
import os from 'os' | ||
import extract from 'extract-zip'; | ||
import path from 'path'; | ||
import {ObjectLiteral} from "@restroom-mw/types"; | ||
require("dotenv").config(); | ||
/** | ||
@@ -25,2 +27,14 @@ * `download the 'myUrl' and extract it into 'myFolder'` | ||
import {READ} from "./actions"; | ||
/** | ||
* Base dir to store data for the user | ||
* @constant | ||
* @type {string} | ||
*/ | ||
export const FILES_DIR = process.env.FILES_DIR; | ||
let input: ObjectLiteral = {}; | ||
// save path must be subdirs of FILES_DIR | ||
@@ -43,2 +57,22 @@ const validatePath = (p: string) => { | ||
rr.onBefore(async (params) => { | ||
const { zencode, keys, data } = params; | ||
if (zencode.match(READ)) { | ||
const params = zencode.paramsOf(READ); | ||
for(const file of params) { | ||
validatePath(file); | ||
const absoluteFile = path.join(FILES_DIR, file) | ||
try { | ||
const content = fs.readFileSync(absoluteFile, 'utf8') | ||
Object.assign(data, JSON.parse(content)) | ||
} catch(e) { | ||
throw new Error(`[FILES] error while reading the file ${absoluteFile}`); | ||
} | ||
} | ||
} | ||
input = rr.combineDataKeys(data, keys); | ||
}); | ||
rr.onSuccess(async (params) => { | ||
@@ -49,27 +83,31 @@ const {result, zencode} = params; | ||
for (let i = 0; i < allPassOutputs.length; i += 2) { | ||
const file = result[allPassOutputs[i]] | ||
const folder = result[allPassOutputs[i + 1]] | ||
const file = result[allPassOutputs[i]] || | ||
input[allPassOutputs[i]]; | ||
const folder = result[allPassOutputs[i + 1]] || | ||
input[allPassOutputs[i + 1]]; | ||
if (file && folder) { | ||
try { | ||
const absoluteFolder = path.resolve(FILES_DIR + "/" + folder); | ||
validatePath(absoluteFolder); | ||
if(!file) { | ||
throw new Error(`[FILES] url not defined`); | ||
} | ||
if(!folder) { | ||
throw new Error(`[FILES] destination folder not defined ${Object.keys(input)}`); | ||
} | ||
const response = await axios.get(file, { | ||
responseType: 'arraybuffer' | ||
}); | ||
const tempdir = fs.mkdtempSync("/tmp/restroom"); | ||
const tempfile = tempdir + "/downloaded"; | ||
fs.writeFileSync(tempfile, response.data); | ||
await extract(tempfile, {dir: absoluteFolder}); | ||
fs.unlinkSync(tempfile); | ||
fs.rmdirSync(tempdir); | ||
} catch (e) { | ||
next(e); | ||
throw new Error(`[FILES] Error sending the result to "${file}": ${e}`); | ||
} | ||
try { | ||
const absoluteFolder = path.resolve(path.join(FILES_DIR, folder)); | ||
validatePath(absoluteFolder); | ||
const response = await axios.get(file, { | ||
responseType: 'arraybuffer' | ||
}); | ||
const tempdir = fs.mkdtempSync(path.join(os.tmpdir(), 'restroom-')); | ||
const tempfile = path.join(tempdir, "downloaded"); | ||
fs.writeFileSync(tempfile, response.data); | ||
await extract(tempfile, { dir: absoluteFolder }); | ||
fs.unlinkSync(tempfile); | ||
fs.rmdirSync(tempdir); | ||
} catch (e) { | ||
next(e); | ||
throw new Error(`[FILES] Error sending the result to "${file}": ${e}`); | ||
} | ||
else { | ||
throw new Error(`[FILES] url or destination folder not defined`); | ||
} | ||
} | ||
@@ -80,23 +118,27 @@ } | ||
for (let i = 0; i < allPassOutputs.length; i += 2) { | ||
const variable = result[allPassOutputs[i]] | ||
const file = result[allPassOutputs[i + 1]] | ||
const variable = result[allPassOutputs[i]] || | ||
input[allPassOutputs[i]]; | ||
const file = result[allPassOutputs[i + 1]] || | ||
input[allPassOutputs[i + 1]]; | ||
if (variable && file) { | ||
const variableJson = JSON.stringify(variable) | ||
try { | ||
const absoluteFile = path.resolve(FILES_DIR + "/" + file); | ||
validatePath(absoluteFile); | ||
if(!variable) { | ||
throw new Error(`[FILES] variable not defined`); | ||
} | ||
if(!file) { | ||
throw new Error(`[FILES] destination file not defined`); | ||
} | ||
const absoluteFolder = path.dirname(absoluteFile); | ||
fs.mkdirSync(absoluteFolder, {recursive: true}); | ||
const variableJson = JSON.stringify(variable) | ||
try { | ||
const absoluteFile = path.resolve(path.join(FILES_DIR, file)); | ||
validatePath(absoluteFile); | ||
fs.writeFileSync(absoluteFile, variableJson); | ||
} catch (e) { | ||
next(e); | ||
throw new Error(`[FILES] Error saving the result to "${file}": ${e}`); | ||
} | ||
const absoluteFolder = path.dirname(absoluteFile); | ||
fs.mkdirSync(absoluteFolder, { recursive: true }); | ||
fs.writeFileSync(absoluteFile, variableJson); | ||
} catch (e) { | ||
next(e); | ||
throw new Error(`[FILES] Error saving the result to "${file}": ${e}`); | ||
} | ||
else { | ||
throw new Error(`[FILES] variable or destination folder not defined`); | ||
} | ||
} | ||
@@ -103,0 +145,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
47829
285
2