eslint-plugin-security 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslint-doc-generatorrc.js +9 -0
- package/.eslintrc +29 -1
- package/.github/ISSUE_TEMPLATE/bug-report.yml +85 -0
- package/.github/ISSUE_TEMPLATE/new-rule.yml +39 -0
- package/.github/ISSUE_TEMPLATE/rule-change.yml +61 -0
- package/.github/workflows/ci.yml +55 -0
- package/.github/workflows/pr.yml +19 -0
- package/.github/workflows/release-please.yml +39 -0
- package/.markdownlint.json +4 -0
- package/.markdownlintignore +3 -0
- package/.prettierrc.json +7 -0
- package/CHANGELOG.md +114 -34
- package/README.md +45 -85
- package/docs/avoid-command-injection-node.md +85 -0
- package/docs/bypass-connect-csrf-protection-by-abusing.md +42 -0
- package/docs/regular-expression-dos-and-node.md +83 -0
- package/docs/rules/detect-bidi-characters.md +50 -0
- package/docs/rules/detect-buffer-noassert.md +9 -0
- package/docs/rules/detect-child-process.md +9 -0
- package/docs/rules/detect-disable-mustache-escape.md +9 -0
- package/docs/rules/detect-eval-with-expression.md +7 -0
- package/docs/rules/detect-new-buffer.md +5 -0
- package/docs/rules/detect-no-csrf-before-method-override.md +9 -0
- package/docs/rules/detect-non-literal-fs-filename.md +7 -0
- package/docs/rules/detect-non-literal-regexp.md +7 -0
- package/docs/rules/detect-non-literal-require.md +7 -0
- package/docs/rules/detect-object-injection.md +7 -0
- package/docs/rules/detect-possible-timing-attacks.md +5 -0
- package/docs/rules/detect-pseudoRandomBytes.md +5 -0
- package/docs/rules/detect-unsafe-regex.md +7 -0
- package/docs/the-dangers-of-square-bracket-notation.md +107 -0
- package/index.js +10 -9
- package/package.json +34 -7
- package/rules/detect-bidi-characters.js +101 -0
- package/rules/detect-buffer-noassert.js +66 -55
- package/rules/detect-child-process.js +57 -25
- package/rules/detect-disable-mustache-escape.js +24 -14
- package/rules/detect-eval-with-expression.js +19 -9
- package/rules/detect-new-buffer.js +19 -16
- package/rules/detect-no-csrf-before-method-override.js +32 -25
- package/rules/detect-non-literal-fs-filename.js +86 -33
- package/rules/detect-non-literal-regexp.js +24 -18
- package/rules/detect-non-literal-require.js +25 -17
- package/rules/detect-object-injection.js +61 -59
- package/rules/detect-possible-timing-attacks.js +40 -42
- package/rules/detect-pseudoRandomBytes.js +18 -11
- package/rules/detect-unsafe-regex.js +36 -23
- package/test/detect-bidi-characters.js +74 -0
- package/test/detect-buffer-noassert.js +18 -18
- package/test/detect-child-process.js +49 -23
- package/test/detect-disable-mustache-escape.js +3 -4
- package/test/detect-eval-with-expression.js +4 -5
- package/test/detect-new-buffer.js +4 -5
- package/test/detect-no-csrf-before-method-override.js +3 -4
- package/test/detect-non-literal-fs-filename.js +135 -9
- package/test/detect-non-literal-regexp.js +5 -6
- package/test/detect-non-literal-require.js +11 -8
- package/test/detect-object-injection.js +3 -5
- package/test/detect-possible-timing-attacks.js +8 -10
- package/test/detect-pseudoRandomBytes.js +3 -4
- package/test/detect-unsafe-regexp.js +9 -11
- package/test/utils/import-utils.js +172 -0
- package/utils/data/fsFunctionData.json +51 -0
- package/utils/import-utils.js +196 -0
- package/.npmignore +0 -1
- package/rules/data/fsFunctionData.json +0 -51
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { getImportAccessPath } = require('../../utils/import-utils');
|
|
4
|
+
const { deepStrictEqual } = require('assert');
|
|
5
|
+
|
|
6
|
+
const Linter = require('eslint').Linter;
|
|
7
|
+
|
|
8
|
+
function getGetImportAccessPathResult(code) {
|
|
9
|
+
const linter = new Linter();
|
|
10
|
+
const result = [];
|
|
11
|
+
linter.defineRule('test-rule', {
|
|
12
|
+
create(context) {
|
|
13
|
+
return {
|
|
14
|
+
'Identifier[name = target]'(node) {
|
|
15
|
+
let expr = node;
|
|
16
|
+
if (node.parent.type === 'MemberExpression' && node.parent.property === node) {
|
|
17
|
+
expr = node.parent;
|
|
18
|
+
}
|
|
19
|
+
const info = getImportAccessPath({
|
|
20
|
+
node: expr,
|
|
21
|
+
scope: context.getScope(),
|
|
22
|
+
packageNames: ['target', 'target-foo', 'target-bar'],
|
|
23
|
+
});
|
|
24
|
+
if (!info) return;
|
|
25
|
+
result.push({
|
|
26
|
+
path: info.path,
|
|
27
|
+
packageName: info.packageName,
|
|
28
|
+
...(info.defaultImport ? { defaultImport: info.defaultImport } : {}),
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const linterResult = linter.verify(code, {
|
|
36
|
+
parserOptions: {
|
|
37
|
+
ecmaVersion: 6,
|
|
38
|
+
sourceType: 'module',
|
|
39
|
+
},
|
|
40
|
+
rules: {
|
|
41
|
+
'test-rule': 'error',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
deepStrictEqual(linterResult, []);
|
|
45
|
+
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
describe('getImportAccessPath', () => {
|
|
50
|
+
describe('The result of getImportAccessPath should be as expected.', () => {
|
|
51
|
+
for (const { code, result } of [
|
|
52
|
+
{
|
|
53
|
+
code: `var something = require('target');
|
|
54
|
+
something.target(c);`,
|
|
55
|
+
result: [
|
|
56
|
+
{
|
|
57
|
+
path: ['target'],
|
|
58
|
+
packageName: 'target',
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
code: `var target = require('target');
|
|
64
|
+
target(c);
|
|
65
|
+
var { foo } = require('target-foo');
|
|
66
|
+
foo.target(c);
|
|
67
|
+
foo.bar.target(c);
|
|
68
|
+
var { a: bar } = require('target-bar');
|
|
69
|
+
bar.target(c);
|
|
70
|
+
var baz = require('target-baz');
|
|
71
|
+
baz.target(c);
|
|
72
|
+
var qux = qux.foo.target;`,
|
|
73
|
+
result: [
|
|
74
|
+
{
|
|
75
|
+
path: [],
|
|
76
|
+
packageName: 'target',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
path: [],
|
|
80
|
+
packageName: 'target',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
path: ['foo', 'target'],
|
|
84
|
+
packageName: 'target-foo',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
path: ['foo', 'bar', 'target'],
|
|
88
|
+
packageName: 'target-foo',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
path: ['a', 'target'],
|
|
92
|
+
packageName: 'target-bar',
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
code: `require('target').target;
|
|
98
|
+
function fn () {
|
|
99
|
+
var { foo } = require('target-foo');
|
|
100
|
+
foo.target(c);
|
|
101
|
+
}`,
|
|
102
|
+
result: [
|
|
103
|
+
{
|
|
104
|
+
path: ['target'],
|
|
105
|
+
packageName: 'target',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
path: ['foo', 'target'],
|
|
109
|
+
packageName: 'target-foo',
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
code: `import { foo } from 'target-foo';
|
|
115
|
+
foo.target(c);
|
|
116
|
+
foo.bar.target(c);
|
|
117
|
+
import { a as bar } from 'target-bar';
|
|
118
|
+
bar.target(c);
|
|
119
|
+
import baz from 'target-baz';
|
|
120
|
+
baz.target(c);`,
|
|
121
|
+
result: [
|
|
122
|
+
{
|
|
123
|
+
path: ['foo', 'target'],
|
|
124
|
+
packageName: 'target-foo',
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
path: ['foo', 'bar', 'target'],
|
|
128
|
+
packageName: 'target-foo',
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
path: ['a', 'target'],
|
|
132
|
+
packageName: 'target-bar',
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
code: `import foo from 'target-foo';
|
|
138
|
+
foo.target(c);
|
|
139
|
+
import * as bar from 'target-bar';
|
|
140
|
+
bar.target(c);`,
|
|
141
|
+
result: [
|
|
142
|
+
{
|
|
143
|
+
path: ['target'],
|
|
144
|
+
defaultImport: true,
|
|
145
|
+
packageName: 'target-foo',
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
path: ['target'],
|
|
149
|
+
packageName: 'target-bar',
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
code: `import foo from 'target-foo';
|
|
155
|
+
function fn () {
|
|
156
|
+
foo.target(c);
|
|
157
|
+
}`,
|
|
158
|
+
result: [
|
|
159
|
+
{
|
|
160
|
+
path: ['target'],
|
|
161
|
+
defaultImport: true,
|
|
162
|
+
packageName: 'target-foo',
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
]) {
|
|
167
|
+
it(code, () => {
|
|
168
|
+
deepStrictEqual(getGetImportAccessPathResult(code), result);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"appendFile": [0],
|
|
3
|
+
"appendFileSync": [0],
|
|
4
|
+
"chmod": [0],
|
|
5
|
+
"chmodSync": [0],
|
|
6
|
+
"chown": [0],
|
|
7
|
+
"chownSync": [0],
|
|
8
|
+
"createReadStream": [0],
|
|
9
|
+
"createWriteStream": [0],
|
|
10
|
+
"exists": [0],
|
|
11
|
+
"existsSync": [0],
|
|
12
|
+
"lchmod": [0],
|
|
13
|
+
"lchmodSync": [0],
|
|
14
|
+
"lchown": [0],
|
|
15
|
+
"lchownSync": [0],
|
|
16
|
+
"link": [0, 1],
|
|
17
|
+
"linkSync": [0, 1],
|
|
18
|
+
"lstat": [0],
|
|
19
|
+
"lstatSync": [0],
|
|
20
|
+
"mkdir": [0],
|
|
21
|
+
"mkdirSync": [0],
|
|
22
|
+
"open": [0],
|
|
23
|
+
"openSync": [0],
|
|
24
|
+
"readdir": [0],
|
|
25
|
+
"readdirSync": [0],
|
|
26
|
+
"readFile": [0],
|
|
27
|
+
"readFileSync": [0],
|
|
28
|
+
"readlink": [0],
|
|
29
|
+
"readlinkSync": [0],
|
|
30
|
+
"realpath": [0],
|
|
31
|
+
"realpathSync": [0],
|
|
32
|
+
"rename": [0, 1],
|
|
33
|
+
"renameSync": [0, 1],
|
|
34
|
+
"rmdir": [0],
|
|
35
|
+
"rmdirSync": [0],
|
|
36
|
+
"stat": [0],
|
|
37
|
+
"statSync": [0],
|
|
38
|
+
"symlink": [0, 1],
|
|
39
|
+
"symlinkSync": [0, 1],
|
|
40
|
+
"truncate": [0],
|
|
41
|
+
"truncateSync": [0],
|
|
42
|
+
"unlink": [0],
|
|
43
|
+
"unlinkSync": [0],
|
|
44
|
+
"unwatchFile": [0],
|
|
45
|
+
"utimes": [0],
|
|
46
|
+
"utimesSync": [0],
|
|
47
|
+
"watch": [0],
|
|
48
|
+
"watchFile": [0],
|
|
49
|
+
"writeFile": [0],
|
|
50
|
+
"writeFileSync": [0]
|
|
51
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
module.exports.getImportAccessPath = getImportAccessPath;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {Object} ImportAccessPathInfo
|
|
5
|
+
* @property {string[]} path
|
|
6
|
+
* @property {boolean} [defaultImport]
|
|
7
|
+
* @property {string} packageName
|
|
8
|
+
* @property {import("estree").SimpleCallExpression | import("estree").ImportDeclaration} node
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Returns the access path information from a require or import
|
|
12
|
+
*
|
|
13
|
+
* @param {Object} params
|
|
14
|
+
* @param {import("estree").Expression} params.node The node to check.
|
|
15
|
+
* @param {import("eslint").Scope.Scope} params.scope The scope of the given node.
|
|
16
|
+
* @param {string[]} params.packageNames The interesting packages the method is imported from
|
|
17
|
+
* @returns {ImportAccessPathInfo | null}
|
|
18
|
+
*/
|
|
19
|
+
function getImportAccessPath({ node, scope, packageNames }) {
|
|
20
|
+
const tracked = new Set();
|
|
21
|
+
return getImportAccessPathInternal(node);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {import("estree").Expression} node
|
|
25
|
+
* @returns {ImportAccessPathInfo | null}
|
|
26
|
+
*/
|
|
27
|
+
function getImportAccessPathInternal(node) {
|
|
28
|
+
if (tracked.has(node)) {
|
|
29
|
+
// Guard infinite loops.
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
tracked.add(node);
|
|
33
|
+
|
|
34
|
+
if (node.type === 'Identifier') {
|
|
35
|
+
// Track variables.
|
|
36
|
+
const variable = findVariable(scope, node.name);
|
|
37
|
+
if (!variable) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
// Check variables defined in `var foo = ...`.
|
|
41
|
+
const declDef = variable.defs.find(
|
|
42
|
+
/** @returns {def is import("eslint").Scope.Definition & {type: 'Variable'}} */
|
|
43
|
+
(def) => def.type === 'Variable' && def.node.type === 'VariableDeclarator' && def.node.init
|
|
44
|
+
);
|
|
45
|
+
if (declDef) {
|
|
46
|
+
let propName = null;
|
|
47
|
+
if (declDef.node.id.type === 'ObjectPattern') {
|
|
48
|
+
const property = declDef.node.id.properties.find((property) => property.type === 'Property' && property.value.type === 'Identifier' && property.value.name === node.name);
|
|
49
|
+
if (property && !property.computed) {
|
|
50
|
+
propName = property.key.name;
|
|
51
|
+
}
|
|
52
|
+
} else if (declDef.node.id.type !== 'Identifier') {
|
|
53
|
+
// Unknown access path
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const nesting = getImportAccessPathInternal(declDef.node.init);
|
|
57
|
+
if (!nesting) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Detects:
|
|
62
|
+
* | var something = require('package-name');
|
|
63
|
+
* | something(c);
|
|
64
|
+
* , or
|
|
65
|
+
* | var { propName: something } = require('package-name');
|
|
66
|
+
* | something(c);
|
|
67
|
+
*/
|
|
68
|
+
return {
|
|
69
|
+
path: propName ? [...nesting.path, propName] : nesting.path,
|
|
70
|
+
defaultImport: nesting.defaultImport,
|
|
71
|
+
packageName: nesting.packageName,
|
|
72
|
+
node: nesting.node,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Check variables defined in `import foo from ...`.
|
|
76
|
+
const importDef = variable.defs.find(
|
|
77
|
+
/** @returns {def is import("eslint").Scope.Definition & {type: 'ImportBinding'}} */
|
|
78
|
+
(def) =>
|
|
79
|
+
def.type === 'ImportBinding' &&
|
|
80
|
+
(def.node.type === 'ImportDefaultSpecifier' || def.node.type === 'ImportNamespaceSpecifier' || def.node.type === 'ImportSpecifier') &&
|
|
81
|
+
isImportDeclaration(def.node.parent)
|
|
82
|
+
);
|
|
83
|
+
if (importDef) {
|
|
84
|
+
let propName = null;
|
|
85
|
+
let defaultImport;
|
|
86
|
+
if (importDef.node.type === 'ImportSpecifier') {
|
|
87
|
+
propName = importDef.node.imported.name;
|
|
88
|
+
} else if (importDef.node.type === 'ImportDefaultSpecifier') {
|
|
89
|
+
defaultImport = true;
|
|
90
|
+
} else if (importDef.node.type !== 'ImportNamespaceSpecifier') {
|
|
91
|
+
// Unknown access path
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Detects:
|
|
96
|
+
* | import { propName as something } from 'package-name';
|
|
97
|
+
* | something(c);
|
|
98
|
+
* ,
|
|
99
|
+
* | import * as something from 'package-name';
|
|
100
|
+
* | something(c);
|
|
101
|
+
* , or
|
|
102
|
+
* | import something from 'package-name';
|
|
103
|
+
* | something(c);
|
|
104
|
+
*/
|
|
105
|
+
return {
|
|
106
|
+
path: propName ? [propName] : [],
|
|
107
|
+
defaultImport: defaultImport,
|
|
108
|
+
packageName: importDef.node.parent.source.value,
|
|
109
|
+
node: importDef.node.parent,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
} else if (node.type === 'MemberExpression') {
|
|
114
|
+
if (node.computed) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
const nesting = getImportAccessPathInternal(node.object);
|
|
118
|
+
if (!nesting) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Detects:
|
|
123
|
+
* | var something = require('package-name');
|
|
124
|
+
* | something.propName(c);
|
|
125
|
+
* ,
|
|
126
|
+
* | var { something } = require('package-name');
|
|
127
|
+
* | something.propName(c);
|
|
128
|
+
* ,
|
|
129
|
+
* | import something from 'package-name';
|
|
130
|
+
* | something.propName(c);
|
|
131
|
+
* ,
|
|
132
|
+
* | import * as something from 'package-name';
|
|
133
|
+
* | something.propName(c);
|
|
134
|
+
* , or
|
|
135
|
+
* | import { something } from 'package-name';
|
|
136
|
+
* | something.propName(c);
|
|
137
|
+
*/
|
|
138
|
+
return {
|
|
139
|
+
path: [...nesting.path, node.property.name],
|
|
140
|
+
defaultImport: nesting.defaultImport,
|
|
141
|
+
packageName: nesting.packageName,
|
|
142
|
+
node: nesting.node,
|
|
143
|
+
};
|
|
144
|
+
} else if (isRequireBasedImport(node)) {
|
|
145
|
+
/**
|
|
146
|
+
* Detects:
|
|
147
|
+
* | require('package-name');
|
|
148
|
+
* ,
|
|
149
|
+
* | require('package-name').propName(c);
|
|
150
|
+
* , or
|
|
151
|
+
* | require('package-name')(c);
|
|
152
|
+
*/
|
|
153
|
+
return {
|
|
154
|
+
path: [],
|
|
155
|
+
packageName: node.arguments[0].value,
|
|
156
|
+
node,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Checks whether the given expression node is a require based import, or not
|
|
164
|
+
* @param {import("estree").Expression} expression
|
|
165
|
+
*/
|
|
166
|
+
function isRequireBasedImport(expression) {
|
|
167
|
+
return (
|
|
168
|
+
expression &&
|
|
169
|
+
expression.type === 'CallExpression' &&
|
|
170
|
+
expression.callee.name === 'require' &&
|
|
171
|
+
expression.arguments.length &&
|
|
172
|
+
expression.arguments[0].type === 'Literal' &&
|
|
173
|
+
packageNames.includes(expression.arguments[0].value)
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Checks whether the given node is a import, or not
|
|
179
|
+
* @param {import("estree").Node} node
|
|
180
|
+
*/
|
|
181
|
+
function isImportDeclaration(node) {
|
|
182
|
+
return node && node.type === 'ImportDeclaration' && packageNames.includes(node.source.value);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** @returns {import("eslint").Scope.Variable | null} */
|
|
187
|
+
function findVariable(scope, name) {
|
|
188
|
+
while (scope != null) {
|
|
189
|
+
const variable = scope.set.get(name);
|
|
190
|
+
if (variable != null) {
|
|
191
|
+
return variable;
|
|
192
|
+
}
|
|
193
|
+
scope = scope.upper;
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
package/.npmignore
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
node_modules
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"appendFile": [0],
|
|
3
|
-
"appendFileSync": [0],
|
|
4
|
-
"chmod": [0],
|
|
5
|
-
"chmodSync": [0],
|
|
6
|
-
"chown": [0],
|
|
7
|
-
"chownSync": [0],
|
|
8
|
-
"createReadStream": [0],
|
|
9
|
-
"createWriteStream": [0],
|
|
10
|
-
"exists": [0],
|
|
11
|
-
"existsSync": [0],
|
|
12
|
-
"lchmod": [0],
|
|
13
|
-
"lchmodSync": [0],
|
|
14
|
-
"lchown": [0],
|
|
15
|
-
"lchownSync": [0],
|
|
16
|
-
"link": [0,1],
|
|
17
|
-
"linkSync": [0,1],
|
|
18
|
-
"lstat": [0],
|
|
19
|
-
"lstatSync": [0],
|
|
20
|
-
"mkdir": [0],
|
|
21
|
-
"mkdirSync": [0],
|
|
22
|
-
"open": [0],
|
|
23
|
-
"openSync": [0],
|
|
24
|
-
"readdir": [0],
|
|
25
|
-
"readdirSync": [0],
|
|
26
|
-
"readFile": [0],
|
|
27
|
-
"readFileSync": [0],
|
|
28
|
-
"readlink": [0],
|
|
29
|
-
"readlinkSync": [0],
|
|
30
|
-
"realpath": [0],
|
|
31
|
-
"realpathSync": [0],
|
|
32
|
-
"rename": [0,1],
|
|
33
|
-
"renameSync": [0,1],
|
|
34
|
-
"rmdir": [0],
|
|
35
|
-
"rmdirSync": [0],
|
|
36
|
-
"stat": [0],
|
|
37
|
-
"statSync": [0],
|
|
38
|
-
"symlink": [0,1],
|
|
39
|
-
"symlinkSync": [0,1],
|
|
40
|
-
"truncate": [0],
|
|
41
|
-
"truncateSync": [0],
|
|
42
|
-
"unlink": [0],
|
|
43
|
-
"unlinkSync": [0],
|
|
44
|
-
"unwatchFile": [0],
|
|
45
|
-
"utimes": [0],
|
|
46
|
-
"utimesSync": [0],
|
|
47
|
-
"watch": [0],
|
|
48
|
-
"watchFile": [0],
|
|
49
|
-
"writeFile": [0],
|
|
50
|
-
"writeFileSync": [0]
|
|
51
|
-
}
|