Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@restroom-mw/files

Package Overview
Dependencies
Maintainers
3
Versions
96
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@restroom-mw/files - npm Package Compare versions

Comparing version 0.13.1-b5b2bd4.43 to 0.13.1-b611a0f.118

66

dist/actions.d.ts

@@ -1,4 +0,64 @@

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 {}";
export declare enum Action {
/**
* `Then I download the 'myUrl' and extract it into 'myFolder'`<br><br>
* Download a zip file located at the url *myUrl* and extract it at the path
* *myFolder* under the *FILES_DIR* on the server.
* @param {string} myUrl - Name of the variable containing the url
* @param {string} myFolder - Name of the variable containing the path to
* the folder where the data will be stored
*/
DOWNLOAD = "download the {} and extract it into {}",
/**
* `Then I store 'myVariable' in the file 'myFile'`<br><br>
* Store the content of the variable *myVariable* in the filesystem at the path
* *myFile* under the *FILES_DIR* directory on the server
* @param {string} myVariable - Name of the variable containing the data to be stored
* @param {string} myFile - Name of the variable containing the path to the file where
* the data will be stored
*/
STORE_RESULT = "store {} in the file {}",
/**
* `Given I read the content of 'myFile'`<br><br>
* write the content of *myFile*, found under the *FILES_DIR* directory, in the data
* @param {string} myFile - It can be the name of the variable that contains the path
* to the file or the path itself
*/
READ = "read the content of {}",
/**
* `Given I read the content of 'myFile' and save the output into 'myVariable'`<br><br>
* Write the content of *myFile* in the data under the key *myVariable*
* @param {string} myFile - It can be the name of the variable that contains the path
* to the file or the path itself
* @param {string} myVariable - Name of the variable where the content of the file will be stored
*/
READ_AND_SAVE = "read the content of {} and save the output into {}",
/**
* `Given I list the content of directory 'dir_path' as 'dir_result'`<br><br>
* Write the list of objects found in *dir_path*, under the *FILES_DIR* directory, in the data,
* the result is an array of dictionaries whose structure is:
* ```
* {
* atime: '2022-06-13T07:00:34.870Z',
* birthtime: '2022-06-13T07:00:34.870Z',
* blksize: 4096,
* blocks: 8,
* ctime: '2022-08-09T11:09:22.718Z',
* dev: 2055,
* gid: 1000,
* mode: '40755',
* mtime: '2022-08-09T11:09:22.718Z',
* name: 'zencode',
* nlink: 6,
* size: 4096,
* uid: 1000
* }
* ```
* In particular, if `mode` starts with `40` the current item is a directory
*
* @param {string} dir_path - Variable name containing the path to the directory
* under the *FILES_DIR* directory
* @param {string} dir_result - Name of the variable where the result will be stored
*/
LS = "list the content of directory {} as {}"
}
//# sourceMappingURL=actions.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
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 {}";
exports.Action = void 0;
var Action;
(function (Action) {
/**
* `Then I download the 'myUrl' and extract it into 'myFolder'`<br><br>
* Download a zip file located at the url *myUrl* and extract it at the path
* *myFolder* under the *FILES_DIR* on the server.
* @param {string} myUrl - Name of the variable containing the url
* @param {string} myFolder - Name of the variable containing the path to
* the folder where the data will be stored
*/
Action["DOWNLOAD"] = "download the {} and extract it into {}";
/**
* `Then I store 'myVariable' in the file 'myFile'`<br><br>
* Store the content of the variable *myVariable* in the filesystem at the path
* *myFile* under the *FILES_DIR* directory on the server
* @param {string} myVariable - Name of the variable containing the data to be stored
* @param {string} myFile - Name of the variable containing the path to the file where
* the data will be stored
*/
Action["STORE_RESULT"] = "store {} in the file {}";
/**
* `Given I read the content of 'myFile'`<br><br>
* write the content of *myFile*, found under the *FILES_DIR* directory, in the data
* @param {string} myFile - It can be the name of the variable that contains the path
* to the file or the path itself
*/
Action["READ"] = "read the content of {}";
/**
* `Given I read the content of 'myFile' and save the output into 'myVariable'`<br><br>
* Write the content of *myFile* in the data under the key *myVariable*
* @param {string} myFile - It can be the name of the variable that contains the path
* to the file or the path itself
* @param {string} myVariable - Name of the variable where the content of the file will be stored
*/
Action["READ_AND_SAVE"] = "read the content of {} and save the output into {}";
/**
* `Given I list the content of directory 'dir_path' as 'dir_result'`<br><br>
* Write the list of objects found in *dir_path*, under the *FILES_DIR* directory, in the data,
* the result is an array of dictionaries whose structure is:
* ```
* {
* atime: '2022-06-13T07:00:34.870Z',
* birthtime: '2022-06-13T07:00:34.870Z',
* blksize: 4096,
* blocks: 8,
* ctime: '2022-08-09T11:09:22.718Z',
* dev: 2055,
* gid: 1000,
* mode: '40755',
* mtime: '2022-08-09T11:09:22.718Z',
* name: 'zencode',
* nlink: 6,
* size: 4096,
* uid: 1000
* }
* ```
* In particular, if `mode` starts with `40` the current item is a directory
*
* @param {string} dir_path - Variable name containing the path to the directory
* under the *FILES_DIR* directory
* @param {string} dir_result - Name of the variable where the result will be stored
*/
Action["LS"] = "list the content of directory {} as {}";
})(Action = exports.Action || (exports.Action = {}));

125

dist/index.js

@@ -19,22 +19,10 @@ "use strict";

const fs_1 = __importDefault(require("fs"));
const promises_1 = require("node:fs/promises");
const os_1 = __importDefault(require("os"));
const extract_zip_1 = __importDefault(require("extract-zip"));
const path_1 = __importDefault(require("path"));
const utils_1 = require("@restroom-mw/utils");
const actions_1 = require("./actions");
require("dotenv").config();
/**
* `download the 'myUrl' and extract it into 'myFolder'`
*
* Download a zip file located at the url `myUrl` and extract it at the path
* `myFolder` on the server.
*/
const actions_1 = require("./actions");
/**
* `store 'myVariable' in the file 'myFolder'`
*
* Store the content of the variable `myVariable` in the filesystem at the path
* `myFolder` on the server
*/
const actions_2 = require("./actions");
const actions_3 = require("./actions");
/**
* Base dir to store data for the user

@@ -47,13 +35,3 @@ * @constant

// save path must be subdirs of FILES_DIR
const validatePath = (p) => {
if (!exports.FILES_DIR)
throw new Error(`FILES_DIR is not defined`);
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 ${exports.FILES_DIR}`);
}
}
};
const validatePath = (0, utils_1.validateSubdir)(exports.FILES_DIR);
exports.default = (req, res, next) => {

@@ -63,15 +41,74 @@ const rr = new core_1.Restroom(req, res);

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);
input = rr.combineDataKeys(data, keys);
const readFromFile = (file) => {
let content;
const f = input[file] || file;
const absoluteFile = path_1.default.resolve(path_1.default.join(exports.FILES_DIR, f));
validatePath(absoluteFile);
try {
content = fs_1.default.readFileSync(absoluteFile, 'utf8');
}
catch (e) {
// TODO: add not-fatal (warning) log in restroom
//throw new Error(`[FILES] error while reading the file ${absoluteFile}`);
content = "{}";
}
return JSON.parse(content);
};
if (zencode.match(actions_1.Action.READ)) {
const params = zencode.paramsOf(actions_1.Action.READ);
for (const f of params) {
Object.assign(data, readFromFile(f));
}
}
;
if (zencode.match(actions_1.Action.READ_AND_SAVE)) {
const chkParams = zencode.chunkedParamsOf(actions_1.Action.READ_AND_SAVE, 2);
for (const [f, outputVariable] of chkParams) {
data[outputVariable] = readFromFile(f);
}
}
;
if (zencode.match(actions_1.Action.LS)) {
const params = zencode.chunkedParamsOf(actions_1.Action.LS, 2);
const fileStats = {};
const allLs = (yield Promise.all(params.map(([p, name]) => __awaiter(void 0, void 0, void 0, function* () {
const f = input[p] || p;
validatePath(f);
try {
const content = fs_1.default.readFileSync(absoluteFile, 'utf8');
Object.assign(data, JSON.parse(content));
const content = yield (0, promises_1.readdir)(f);
// I am not checking if `name` is used multiple times
fileStats[name] = [];
return content.map((current) => [name, f, current]);
}
catch (e) {
throw new Error(`[FILES] error while reading the file ${absoluteFile}`);
throw new Error(`[FILES] error while reading the file ${f}`);
}
})))).flat();
// list with all files I want to see the stats of
const allStats = yield Promise.all(allLs.map(([name, p, current]) => __awaiter(void 0, void 0, void 0, function* () {
const currentFile = path_1.default.join(p, current);
const fileStat = yield (0, promises_1.stat)(currentFile);
return [name, current, fileStat];
})));
for (const [name, current, currentStat] of allStats) {
// see https://unix.stackexchange.com/questions/317855/file-mode-on-macosx#317907
// for the meaning of the mode field
fileStats[name].push({
'name': current,
'mode': currentStat.mode.toString(8),
'dev': currentStat.dev,
'nlink': currentStat.nlink,
'uid': currentStat.uid,
'gid': currentStat.gid,
'size': currentStat.size,
'blksize': currentStat.blksize,
'blocks': currentStat.blocks,
'atime': currentStat.atime.toISOString(),
'mtime': currentStat.mtime.toISOString(),
'ctime': currentStat.ctime.toISOString(),
'birthtime': currentStat.birthtime.toISOString(),
});
}
Object.assign(data, fileStats);
}

@@ -82,7 +119,9 @@ input = rr.combineDataKeys(data, keys);

const { result, zencode } = params;
if (zencode.match(actions_1.DOWNLOAD)) {
const allPassOutputs = zencode.paramsOf(actions_1.DOWNLOAD);
if (zencode.match(actions_1.Action.DOWNLOAD)) {
const allPassOutputs = zencode.paramsOf(actions_1.Action.DOWNLOAD);
for (let i = 0; i < allPassOutputs.length; i += 2) {
const file = result[allPassOutputs[i]];
const folder = input[allPassOutputs[i + 1]];
const file = result[allPassOutputs[i]] ||
input[allPassOutputs[i]];
const folder = result[allPassOutputs[i + 1]] ||
input[allPassOutputs[i + 1]];
if (!file) {

@@ -113,7 +152,9 @@ throw new Error(`[FILES] url not defined`);

}
if (zencode.match(actions_2.STORE_RESULT)) {
const allPassOutputs = zencode.paramsOf(actions_2.STORE_RESULT);
if (zencode.match(actions_1.Action.STORE_RESULT)) {
const allPassOutputs = zencode.paramsOf(actions_1.Action.STORE_RESULT);
for (let i = 0; i < allPassOutputs.length; i += 2) {
const variable = result[allPassOutputs[i]];
const file = input[allPassOutputs[i + 1]];
const variable = result[allPassOutputs[i]] ||
input[allPassOutputs[i]];
const file = result[allPassOutputs[i + 1]] ||
input[allPassOutputs[i + 1]];
if (!variable) {

@@ -120,0 +161,0 @@ throw new Error(`[FILES] variable not defined`);

{
"name": "@restroom-mw/files",
"version": "0.13.1-b5b2bd4.43+b5b2bd4",
"version": "0.13.1-b611a0f.118+b611a0f",
"description": "Utilities middleware to work with files for Restroom",

@@ -35,3 +35,3 @@ "author": "Alberto Lerda <alberto@dyne.org>",

},
"gitHead": "b5b2bd49465146236746bda33222fd9afa6f0d15"
"gitHead": "b611a0f61ca34654b70487332cafa914851bfa8c"
}

@@ -1,3 +0,63 @@

export const DOWNLOAD = "download the {} and extract it into {}";
export const STORE_RESULT = "store {} in the file {}";
export const READ = "read the content of {}";
export enum Action {
/**
* `Then I download the 'myUrl' and extract it into 'myFolder'`<br><br>
* Download a zip file located at the url *myUrl* and extract it at the path
* *myFolder* under the *FILES_DIR* on the server.
* @param {string} myUrl - Name of the variable containing the url
* @param {string} myFolder - Name of the variable containing the path to
* the folder where the data will be stored
*/
DOWNLOAD = "download the {} and extract it into {}",
/**
* `Then I store 'myVariable' in the file 'myFile'`<br><br>
* Store the content of the variable *myVariable* in the filesystem at the path
* *myFile* under the *FILES_DIR* directory on the server
* @param {string} myVariable - Name of the variable containing the data to be stored
* @param {string} myFile - Name of the variable containing the path to the file where
* the data will be stored
*/
STORE_RESULT = "store {} in the file {}",
/**
* `Given I read the content of 'myFile'`<br><br>
* write the content of *myFile*, found under the *FILES_DIR* directory, in the data
* @param {string} myFile - It can be the name of the variable that contains the path
* to the file or the path itself
*/
READ = "read the content of {}",
/**
* `Given I read the content of 'myFile' and save the output into 'myVariable'`<br><br>
* Write the content of *myFile* in the data under the key *myVariable*
* @param {string} myFile - It can be the name of the variable that contains the path
* to the file or the path itself
* @param {string} myVariable - Name of the variable where the content of the file will be stored
*/
READ_AND_SAVE = "read the content of {} and save the output into {}",
/**
* `Given I list the content of directory 'dir_path' as 'dir_result'`<br><br>
* Write the list of objects found in *dir_path*, under the *FILES_DIR* directory, in the data,
* the result is an array of dictionaries whose structure is:
* ```
* {
* atime: '2022-06-13T07:00:34.870Z',
* birthtime: '2022-06-13T07:00:34.870Z',
* blksize: 4096,
* blocks: 8,
* ctime: '2022-08-09T11:09:22.718Z',
* dev: 2055,
* gid: 1000,
* mode: '40755',
* mtime: '2022-08-09T11:09:22.718Z',
* name: 'zencode',
* nlink: 6,
* size: 4096,
* uid: 1000
* }
* ```
* In particular, if `mode` starts with `40` the current item is a directory
*
* @param {string} dir_path - Variable name containing the path to the directory
* under the *FILES_DIR* directory
* @param {string} dir_result - Name of the variable where the result will be stored
*/
LS = "list the content of directory {} as {}",
}

@@ -5,2 +5,3 @@ import {Restroom} from "@restroom-mw/core";

import fs from 'fs'
import { readdir, stat } from 'node:fs/promises';
import os from 'os'

@@ -10,23 +11,7 @@ import extract from 'extract-zip';

import {ObjectLiteral} from "@restroom-mw/types";
import {validateSubdir} from "@restroom-mw/utils"
import { Action } from "./actions"
require("dotenv").config();
/**
* `download the 'myUrl' and extract it into 'myFolder'`
*
* Download a zip file located at the url `myUrl` and extract it at the path
* `myFolder` on the server.
*/
import {DOWNLOAD} from "./actions";
/**
* `store 'myVariable' in the file 'myFolder'`
*
* Store the content of the variable `myVariable` in the filesystem at the path
* `myFolder` on the server
*/
import {STORE_RESULT} from "./actions";
import {READ} from "./actions";
/**

@@ -42,35 +27,82 @@ * Base dir to store data for the user

// save path must be subdirs of FILES_DIR
const validatePath = (p: string) => {
if (!FILES_DIR)
throw new Error(`FILES_DIR is not defined`);
const validatePath = validateSubdir(FILES_DIR);
if (FILES_DIR != "/") {
const relative = path.relative(FILES_DIR, p);
const isSubdir = relative && !relative.startsWith('..') && !path.isAbsolute(relative);
if (!isSubdir) {
throw new Error(`Result path outside ${FILES_DIR}`)
}
}
}
export default (req: Request, res: Response, next: NextFunction) => {
const rr = new Restroom(req, res);
rr.onBefore(async (params) => {
const { zencode, keys, data } = params;
input = rr.combineDataKeys(data, keys);
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}`);
}
const readFromFile = ( file: string ) => {
let content
const f = input[file] || file;
const absoluteFile = path.resolve(path.join(FILES_DIR, f));
validatePath(absoluteFile);
try {
content = fs.readFileSync(absoluteFile, 'utf8');
} catch(e) {
// TODO: add not-fatal (warning) log in restroom
//throw new Error(`[FILES] error while reading the file ${absoluteFile}`);
content = "{}";
}
return JSON.parse(content);
}
if (zencode.match(Action.READ)) {
const params = zencode.paramsOf(Action.READ);
for(const f of params) {
Object.assign(data, readFromFile(f));
}
};
if (zencode.match(Action.READ_AND_SAVE)) {
const chkParams = zencode.chunkedParamsOf(Action.READ_AND_SAVE, 2);
for(const [f, outputVariable] of chkParams) {
data[ outputVariable ] = readFromFile(f);
}
};
if (zencode.match(Action.LS)) {
const params = zencode.chunkedParamsOf(Action.LS, 2);
const fileStats: Record<string, any> = {}
const allLs = (await Promise.all(params.map(
async ([p, name]: string[]) => {
const f = input[p] || p;
validatePath(f);
try {
const content = await readdir(f)
// I am not checking if `name` is used multiple times
fileStats[name] = []
return content.map((current) => [name, f, current]);
} catch(e) {
throw new Error(`[FILES] error while reading the file ${f}`);
}
}))).flat()
// list with all files I want to see the stats of
const allStats = await Promise.all(allLs.map(async ([name, p, current]) => {
const currentFile = path.join(p, current)
const fileStat = await stat(currentFile)
return [name, current, fileStat]
}))
for(const [name, current, currentStat] of allStats) {
// see https://unix.stackexchange.com/questions/317855/file-mode-on-macosx#317907
// for the meaning of the mode field
fileStats[name].push({
'name': current,
'mode': currentStat.mode.toString(8),
'dev': currentStat.dev,
'nlink': currentStat.nlink,
'uid': currentStat.uid,
'gid': currentStat.gid,
'size': currentStat.size,
'blksize': currentStat.blksize,
'blocks': currentStat.blocks,
'atime': currentStat.atime.toISOString(),
'mtime': currentStat.mtime.toISOString(),
'ctime': currentStat.ctime.toISOString(),
'birthtime': currentStat.birthtime.toISOString(),
})
}
Object.assign(data, fileStats)
}
input = rr.combineDataKeys(data, keys);

@@ -81,7 +113,9 @@ });

const {result, zencode} = params;
if (zencode.match(DOWNLOAD)) {
const allPassOutputs = zencode.paramsOf(DOWNLOAD);
if (zencode.match(Action.DOWNLOAD)) {
const allPassOutputs = zencode.paramsOf(Action.DOWNLOAD);
for (let i = 0; i < allPassOutputs.length; i += 2) {
const file = result[allPassOutputs[i]]
const folder = input[allPassOutputs[i + 1]];
const file = result[allPassOutputs[i]] ||
input[allPassOutputs[i]];
const folder = result[allPassOutputs[i + 1]] ||
input[allPassOutputs[i + 1]];

@@ -114,7 +148,9 @@ if(!file) {

}
if (zencode.match(STORE_RESULT)) {
const allPassOutputs = zencode.paramsOf(STORE_RESULT);
if (zencode.match(Action.STORE_RESULT)) {
const allPassOutputs = zencode.paramsOf(Action.STORE_RESULT);
for (let i = 0; i < allPassOutputs.length; i += 2) {
const variable = result[allPassOutputs[i]]
const file = input[allPassOutputs[i + 1]]
const variable = result[allPassOutputs[i]] ||
input[allPassOutputs[i]];
const file = result[allPassOutputs[i + 1]] ||
input[allPassOutputs[i + 1]];

@@ -121,0 +157,0 @@ if(!variable) {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc