formidable
Advanced tools
Comparing version
{ | ||
"name": "formidable", | ||
"version": "2.1.2", | ||
"version": "2.1.3", | ||
"license": "MIT", | ||
@@ -33,4 +33,4 @@ "description": "A node.js module for parsing form data, especially file uploads.", | ||
"dependencies": { | ||
"@paralleldrive/cuid2": "^2.2.2", | ||
"dezalgo": "^1.0.4", | ||
"hexoid": "^1.0.0", | ||
"once": "^1.4.0", | ||
@@ -40,4 +40,2 @@ "qs": "^6.11.0" | ||
"devDependencies": { | ||
"@commitlint/cli": "8.3.5", | ||
"@commitlint/config-conventional": "8.3.4", | ||
"@tunnckocore/prettier-config": "1.3.8", | ||
@@ -52,5 +50,4 @@ "del-cli": "3.0.0", | ||
"husky": "4.2.5", | ||
"jest": "25.4.0", | ||
"jest": "27.2.4", | ||
"koa": "2.11.0", | ||
"lint-staged": "10.2.7", | ||
"make-dir-cli": "2.0.0", | ||
@@ -75,28 +72,3 @@ "nyc": "15.0.1", | ||
"file" | ||
], | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "git status --porcelain && yarn lint-staged", | ||
"commit-msg": "yarn commitlint -E HUSKY_GIT_PARAMS" | ||
} | ||
}, | ||
"commitlint": { | ||
"extends": [ | ||
"@commitlint/config-conventional" | ||
] | ||
}, | ||
"lint-staged": { | ||
"!*.{js,jsx,ts,tsx}": [ | ||
"yarn run fmt:prepare" | ||
], | ||
"*.{js,jsx,ts,tsx}": [ | ||
"yarn run lint" | ||
] | ||
}, | ||
"renovate": { | ||
"extends": [ | ||
"@tunnckocore", | ||
":pinAllExceptPeerDependencies" | ||
] | ||
} | ||
] | ||
} |
173
README.md
@@ -5,10 +5,21 @@ <p align="center"> | ||
# formidable [![npm version][npmv-img]][npmv-url] [![MIT license][license-img]][license-url] [![Libera Manifesto][libera-manifesto-img]][libera-manifesto-url] [![Twitter][twitter-img]][twitter-url] | ||
# formidable [![npm version][npmv-img]][npmv-url] [![MIT license][license-img]][license-url] [![Libera Manifesto][libera-manifesto-img]][libera-manifesto-url] | ||
> A Node.js module for parsing form data, especially file uploads. | ||
> [!CAUTION] As of April 2025, old versions like v1 and v2 are still the most | ||
> used, while they are deperecated for years -- they are also vulnerable to | ||
> attacks if you are not implementing it properly. **Please upgrade!** We are | ||
> here to help, and AI Editors & Agents could help a lot in such codemod-like | ||
> migrations. | ||
> [!TIP] If you are starting a fresh project, try `formidable@latest` (v3) or | ||
> you can check out the `formidable-mini` which is a super minimal version of | ||
> Formidable (not quite configurable yet, but when it does it could become the | ||
> basis for `formidable@v4`), using web standards like FormData API and File | ||
> API, and you can use it to stream uploads directly to S3 or other such | ||
> services. | ||
[![Code style][codestyle-img]][codestyle-url] | ||
[![codecoverage][codecov-img]][codecov-url] | ||
[![linux build status][linux-build-img]][build-url] | ||
[![windows build status][windows-build-img]][build-url] | ||
[![macos build status][macos-build-img]][build-url] | ||
@@ -19,13 +30,19 @@ | ||
documents.<br /> For bugs reports and feature requests, [please create an | ||
issue][open-issue-url] or ping [@tunnckoCore / @3a1FcBx0](https://twitter.com/3a1FcBx0) | ||
at Twitter. | ||
issue][open-issue-url] or ping | ||
[@wgw_eth / @wgw_lol](https://twitter.com/wgw_eth) at Twitter. | ||
[![Conventional Commits][ccommits-img]][ccommits-url] | ||
[![Minimum Required Nodejs][nodejs-img]][npmv-url] | ||
[![Buy me a Kofi][kofi-img]][kofi-url] | ||
[![Make A Pull Request][prs-welcome-img]][prs-welcome-url] | ||
[![Twitter][twitter-img]][twitter-url] | ||
<!-- [![Conventional Commits][ccommits-img]][ccommits-url] | ||
[![Minimum Required Nodejs][nodejs-img]][npmv-url] | ||
[![Tidelift Subcsription][tidelift-img]][tidelift-url] | ||
[![Buy me a Kofi][kofi-img]][kofi-url] | ||
[![Renovate App Status][renovateapp-img]][renovateapp-url] | ||
[![Make A Pull Request][prs-welcome-img]][prs-welcome-url] | ||
[![Make A Pull Request][prs-welcome-img]][prs-welcome-url] --> | ||
This project is [semantically versioned](https://semver.org) and available as | ||
<!-- This project is [semantically versioned](https://semver.org) and available as | ||
part of the [Tidelift Subscription][tidelift-url] for professional grade | ||
@@ -39,3 +56,3 @@ assurances, enhanced support and security. | ||
improve code health, while paying the maintainers of the exact dependencies you | ||
use._ | ||
use._ --> | ||
@@ -47,3 +64,5 @@ [![][npm-weekly-img]][npmv-url] [![][npm-monthly-img]][npmv-url] | ||
_Check [VERSION NOTES](https://github.com/node-formidable/formidable/blob/master/VERSION_NOTES.md) for more information on v1, v2, and v3 plans, NPM dist-tags and branches._ | ||
_Check | ||
[VERSION NOTES](https://github.com/node-formidable/formidable/blob/master/VERSION_NOTES.md) | ||
for more information on v1, v2, and v3 plans, NPM dist-tags and branches._ | ||
@@ -80,3 +99,5 @@ This module was initially developed by | ||
This is a low-level package, and if you're using a high-level framework it _may_ | ||
already be included. Check the examples below and the [examples/](https://github.com/node-formidable/formidable/tree/master/examples) folder. | ||
already be included. Check the examples below and the | ||
[examples/](https://github.com/node-formidable/formidable/tree/master/examples) | ||
folder. | ||
@@ -93,5 +114,5 @@ ```sh | ||
_**Note:** In near future v3 will be published on the `latest` NPM dist-tag. Future not ready releases will continue to be published on `canary` dist-tag._ | ||
_**Note:** In near future v3 will be published on the `latest` NPM dist-tag. | ||
Future not ready releases will continue to be published on `canary` dist-tag._ | ||
## Examples | ||
@@ -334,8 +355,9 @@ | ||
limit the size of uploaded file. | ||
- `options.maxFields` **{number}** - default `1000`; limit the number of fields, set 0 for unlimited | ||
- `options.maxFields` **{number}** - default `1000`; limit the number of fields, | ||
set 0 for unlimited | ||
- `options.maxFieldsSize` **{number}** - default `20 * 1024 * 1024` (20mb); | ||
limit the amount of memory all fields together (except files) can allocate in | ||
bytes. | ||
- `options.hashAlgorithm` **{string | false}** - default `false`; include checksums calculated | ||
for incoming files, set this to some hash algorithm, see | ||
- `options.hashAlgorithm` **{string | false}** - default `false`; include | ||
checksums calculated for incoming files, set this to some hash algorithm, see | ||
[crypto.createHash](https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm_options) | ||
@@ -364,5 +386,4 @@ for available algorithms | ||
#### `options.filename` **{function}** function (name, ext, part, form) -> string | ||
#### `options.filename` **{function}** function (name, ext, part, form) -> string | ||
_**Note:** If this size of combined fields, or size of some file is exceeded, an | ||
@@ -381,16 +402,15 @@ `'error'` event is fired._ | ||
#### `options.filter` **{function}** function ({name, originalFilename, mimetype}) -> boolean | ||
#### `options.filter` **{function}** function ({name, originalFilename, mimetype}) -> boolean | ||
**Note:** use an outside variable to cancel all uploads upon the first error | ||
**Note:** use an outside variable to cancel all uploads upon the first error | ||
```js | ||
const options = { | ||
filter: function ({name, originalFilename, mimetype}) { | ||
filter: function ({ name, originalFilename, mimetype }) { | ||
// keep only images | ||
return mimetype && mimetype.includes("image"); | ||
} | ||
return mimetype && mimetype.includes('image'); | ||
}, | ||
}; | ||
``` | ||
### .parse(request, callback) | ||
@@ -417,3 +437,4 @@ | ||
About `uploadDir`, given the following directory structure | ||
About `uploadDir`, given the following directory structure | ||
``` | ||
@@ -423,3 +444,3 @@ project-name | ||
│ └── server.js | ||
│ | ||
│ | ||
└── uploads | ||
@@ -431,5 +452,4 @@ └── image.jpg | ||
```js | ||
`${__dirname}/../uploads` | ||
`${__dirname}/../uploads`; | ||
``` | ||
@@ -439,13 +459,14 @@ | ||
Omitting `__dirname` would make the path relative to the current working directory. This would be the same if server.js is launched from src but not project-name. | ||
Omitting `__dirname` would make the path relative to the current working | ||
directory. This would be the same if server.js is launched from src but not | ||
project-name. | ||
`null` will use default which is `os.tmpdir()` | ||
Note: If the directory does not exist, the uploaded files are __silently discarded__. To make sure it exists: | ||
Note: If the directory does not exist, the uploaded files are **silently | ||
discarded**. To make sure it exists: | ||
```js | ||
import {createNecessaryDirectoriesSync} from "filesac"; | ||
import { createNecessaryDirectoriesSync } from 'filesac'; | ||
const uploadPath = `${__dirname}/../uploads`; | ||
@@ -455,3 +476,2 @@ createNecessaryDirectoriesSync(`${uploadPath}/x`); | ||
In the example below, we listen on couple of events and direct them to the | ||
@@ -485,26 +505,29 @@ `data` listener, so you can do whatever you choose there, based on whether its | ||
// If you want to customize whatever you want... | ||
form.on('data', ({ name, key, value, buffer, start, end, formname, ...more }) => { | ||
if (name === 'partBegin') { | ||
} | ||
if (name === 'partData') { | ||
} | ||
if (name === 'headerField') { | ||
} | ||
if (name === 'headerValue') { | ||
} | ||
if (name === 'headerEnd') { | ||
} | ||
if (name === 'headersEnd') { | ||
} | ||
if (name === 'field') { | ||
console.log('field name:', key); | ||
console.log('field value:', value); | ||
} | ||
if (name === 'file') { | ||
console.log('file:', formname, value); | ||
} | ||
if (name === 'fileBegin') { | ||
console.log('fileBegin:', formname, value); | ||
} | ||
}); | ||
form.on( | ||
'data', | ||
({ name, key, value, buffer, start, end, formname, ...more }) => { | ||
if (name === 'partBegin') { | ||
} | ||
if (name === 'partData') { | ||
} | ||
if (name === 'headerField') { | ||
} | ||
if (name === 'headerValue') { | ||
} | ||
if (name === 'headerEnd') { | ||
} | ||
if (name === 'headersEnd') { | ||
} | ||
if (name === 'field') { | ||
console.log('field name:', key); | ||
console.log('field value:', value); | ||
} | ||
if (name === 'file') { | ||
console.log('file:', formname, value); | ||
} | ||
if (name === 'fileBegin') { | ||
console.log('fileBegin:', formname, value); | ||
} | ||
}, | ||
); | ||
``` | ||
@@ -621,3 +644,3 @@ | ||
file.originalFilename: string | null; | ||
// calculated based on options provided | ||
@@ -672,8 +695,8 @@ file.newFilename: string | null; | ||
form.on('fileBegin', (formName, file) => { | ||
// accessible here | ||
// formName the name in the form (<input name="thisname" type="file">) or http filename for octetstream | ||
// file.originalFilename http filename or null if there was a parsing error | ||
// file.newFilename generated hexoid or what options.filename returned | ||
// file.filepath default pathnme as per options.uploadDir and options.filename | ||
// file.filepath = CUSTOM_PATH // to change the final path | ||
// accessible here | ||
// formName the name in the form (<input name="thisname" type="file">) or http filename for octetstream | ||
// file.originalFilename http filename or null if there was a parsing error | ||
// file.newFilename generated hexoid or what options.filename returned | ||
// file.filepath default pathnme as per options.uploadDir and options.filename | ||
// file.filepath = CUSTOM_PATH // to change the final path | ||
}); | ||
@@ -689,5 +712,5 @@ ``` | ||
form.on('file', (formname, file) => { | ||
// same as fileBegin, except | ||
// it is too late to change file.filepath | ||
// file.hash is available if options.hash was used | ||
// same as fileBegin, except | ||
// it is too late to change file.filepath | ||
// file.hash is available if options.hash was used | ||
}); | ||
@@ -787,4 +810,6 @@ ``` | ||
- [Sven Lito](https://github.com/svnlto) for fixing bugs and merging patches | ||
- [egirshov](https://github.com/egirshov) for contributing many improvements to the node-formidable multipart parser | ||
- [Andrew Kelley](https://github.com/superjoe30) for also helping with fixing bugs and making improvements | ||
- [egirshov](https://github.com/egirshov) for contributing many improvements to | ||
the node-formidable multipart parser | ||
- [Andrew Kelley](https://github.com/superjoe30) for also helping with fixing | ||
bugs and making improvements | ||
- [Mike Frey](https://github.com/mikefrey) for contributing JSON support | ||
@@ -817,4 +842,4 @@ | ||
[prs-welcome-url]: http://makeapullrequest.com | ||
[twitter-url]: https://twitter.com/3a1fcBx0 | ||
[twitter-img]: https://badgen.net/twitter/follow/3a1fcBx0?icon=twitter&color=1da1f2&cache=300 | ||
[twitter-url]: https://twitter.com/wgw_eth | ||
[twitter-img]: https://badgen.net/badge/twitter/follow/wgw_eth?icon=twitter&color=1da1f2&cache=30 | ||
@@ -842,6 +867,6 @@ [npm-weekly-img]: https://badgen.net/npm/dw/formidable?icon=npm&cache=300 | ||
[linux-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master/ubuntu?cache=300&label=linux%20build&icon=github | ||
[macos-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master/macos?cache=300&label=macos%20build&icon=github | ||
[linux-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master?label=linux%20build&icon=github | ||
[macos-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master?label=macos%20build&icon=github | ||
[windows-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master/windows?cache=300&label=windows%20build&icon=github | ||
[build-url]: https://github.com/node-formidable/formidable/actions?query=workflow%3Anodejs | ||
[build-url]: https://github.com/node-formidable/formidable/actions | ||
<!-- prettier-ignore-end --> |
@@ -8,3 +8,3 @@ /* eslint-disable class-methods-use-this */ | ||
const path = require('path'); | ||
const hexoid = require('hexoid'); | ||
const cuid2 = require('@paralleldrive/cuid2'); | ||
const once = require('once'); | ||
@@ -16,3 +16,10 @@ const dezalgo = require('dezalgo'); | ||
const toHexoId = hexoid(25); | ||
const CUID2_FINGERPRINT = `${ | ||
process.env.NODE_ENV | ||
}-${os.platform()}-${os.hostname()}-${os.machine()}`; | ||
const createId = cuid2.init({ | ||
length: 25, | ||
fingerprint: CUID2_FINGERPRINT.toLowerCase(), | ||
}); | ||
const DEFAULT_OPTIONS = { | ||
@@ -32,3 +39,3 @@ maxFields: 1000, | ||
defaultInvalidName: 'invalid-name', | ||
filter: function () { | ||
filter() { | ||
return true; | ||
@@ -547,4 +554,2 @@ }, | ||
_joinDirectoryName(name) { | ||
@@ -578,11 +583,12 @@ const newPath = path.join(this.uploadDir, name); | ||
this._getNewName = (part) => { | ||
const name = toHexoId(); | ||
const name = createId(); | ||
if (part && this.options.keepExtensions) { | ||
const originalFilename = typeof part === 'string' ? part : part.originalFilename; | ||
const originalFilename = | ||
typeof part === 'string' ? part : part.originalFilename; | ||
return `${name}${this._getExtension(originalFilename)}`; | ||
} | ||
return name; | ||
} | ||
}; | ||
} | ||
@@ -589,0 +595,0 @@ } |
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
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
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
17
-15%1554
0.45%852
3.02%11
22.22%87431
-7.69%20
-4.76%4
33.33%+ Added
+ Added
+ Added
- Removed
- Removed