exarch-rs 0.1.0 → 0.1.2
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/Cargo.toml +1 -0
- package/README.md +1 -1
- package/biome.json +47 -0
- package/native/exarch-rs.darwin-arm64.node +0 -0
- package/native/exarch-rs.darwin-x64.node +0 -0
- package/native/exarch-rs.linux-arm64-gnu.node +0 -0
- package/native/exarch-rs.linux-x64-gnu.node +0 -0
- package/native/exarch-rs.win32-x64-msvc.node +0 -0
- package/package.json +25 -5
- package/src/config.rs +303 -47
- package/src/error.rs +42 -0
- package/src/lib.rs +560 -17
- package/src/report.rs +538 -0
- package/tests/create.test.js +136 -0
- package/tests/creation-config.test.js +97 -0
- package/tests/extract.test.js +117 -0
- package/tests/list-verify.test.js +172 -0
- package/tests/security-config.test.js +187 -0
- package/index.d.ts +0 -287
package/index.d.ts
DELETED
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* exarch - Memory-safe archive extraction library
|
|
3
|
-
*
|
|
4
|
-
* Provides secure archive extraction with built-in protection against:
|
|
5
|
-
* - Path traversal attacks
|
|
6
|
-
* - Symlink escape attacks
|
|
7
|
-
* - Hardlink escape attacks
|
|
8
|
-
* - Zip bomb attacks
|
|
9
|
-
* - Invalid file permissions
|
|
10
|
-
* - Resource quota violations
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Security configuration for archive extraction.
|
|
15
|
-
*
|
|
16
|
-
* All security features default to deny (secure-by-default policy).
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```typescript
|
|
20
|
-
* // Use secure defaults
|
|
21
|
-
* const config = new SecurityConfig();
|
|
22
|
-
*
|
|
23
|
-
* // Customize with builder pattern
|
|
24
|
-
* const config = new SecurityConfig()
|
|
25
|
-
* .maxFileSize(100 * 1024 * 1024)
|
|
26
|
-
* .allowSymlinks(true);
|
|
27
|
-
*
|
|
28
|
-
* // Use permissive configuration for trusted archives
|
|
29
|
-
* const config = SecurityConfig.permissive();
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
export class SecurityConfig {
|
|
33
|
-
/**
|
|
34
|
-
* Creates a new SecurityConfig with secure defaults.
|
|
35
|
-
*/
|
|
36
|
-
constructor();
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Creates a SecurityConfig with secure defaults.
|
|
40
|
-
* Equivalent to calling the constructor.
|
|
41
|
-
*/
|
|
42
|
-
static default(): SecurityConfig;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Creates a permissive configuration for trusted archives.
|
|
46
|
-
*
|
|
47
|
-
* Enables: symlinks, hardlinks, absolute paths, world-writable files.
|
|
48
|
-
* Use only for archives from trusted sources.
|
|
49
|
-
*/
|
|
50
|
-
static permissive(): SecurityConfig;
|
|
51
|
-
|
|
52
|
-
// Builder pattern methods (chainable)
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Sets the maximum file size in bytes.
|
|
56
|
-
* Default: 50 MB (52,428,800 bytes)
|
|
57
|
-
*/
|
|
58
|
-
maxFileSize(size: number): this;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Sets the maximum total size in bytes.
|
|
62
|
-
* Default: 500 MB (524,288,000 bytes)
|
|
63
|
-
*/
|
|
64
|
-
maxTotalSize(size: number): this;
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Sets the maximum compression ratio.
|
|
68
|
-
* Default: 100.0
|
|
69
|
-
*
|
|
70
|
-
* @throws Error if ratio is not a positive finite number
|
|
71
|
-
*/
|
|
72
|
-
maxCompressionRatio(ratio: number): this;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Sets the maximum file count.
|
|
76
|
-
* Default: 10,000
|
|
77
|
-
*/
|
|
78
|
-
maxFileCount(count: number): this;
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Sets the maximum path depth.
|
|
82
|
-
* Default: 32
|
|
83
|
-
*/
|
|
84
|
-
maxPathDepth(depth: number): this;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Allows or denies symlinks.
|
|
88
|
-
* Default: false (deny)
|
|
89
|
-
*/
|
|
90
|
-
allowSymlinks(allow?: boolean): this;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Allows or denies hardlinks.
|
|
94
|
-
* Default: false (deny)
|
|
95
|
-
*/
|
|
96
|
-
allowHardlinks(allow?: boolean): this;
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Allows or denies absolute paths.
|
|
100
|
-
* Default: false (deny)
|
|
101
|
-
*/
|
|
102
|
-
allowAbsolutePaths(allow?: boolean): this;
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Allows or denies world-writable files.
|
|
106
|
-
* Default: false (deny)
|
|
107
|
-
*/
|
|
108
|
-
allowWorldWritable(allow?: boolean): this;
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Sets whether to preserve permissions from archive.
|
|
112
|
-
* Default: false
|
|
113
|
-
*/
|
|
114
|
-
preservePermissions(preserve?: boolean): this;
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Adds an allowed file extension.
|
|
118
|
-
*
|
|
119
|
-
* @throws Error if extension exceeds maximum length or contains null bytes
|
|
120
|
-
*/
|
|
121
|
-
addAllowedExtension(ext: string): this;
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Adds a banned path component.
|
|
125
|
-
*
|
|
126
|
-
* @throws Error if component exceeds maximum length or contains null bytes
|
|
127
|
-
*/
|
|
128
|
-
addBannedComponent(component: string): this;
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Finalizes the configuration (for API consistency).
|
|
132
|
-
*
|
|
133
|
-
* This method is provided for builder pattern consistency but is optional.
|
|
134
|
-
* The configuration is always valid and can be used directly.
|
|
135
|
-
*/
|
|
136
|
-
build(): this;
|
|
137
|
-
|
|
138
|
-
// Validation methods
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Checks if a path component is allowed.
|
|
142
|
-
*/
|
|
143
|
-
isPathComponentAllowed(component: string): boolean;
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Checks if a file extension is allowed.
|
|
147
|
-
*/
|
|
148
|
-
isExtensionAllowed(extension: string): boolean;
|
|
149
|
-
|
|
150
|
-
// Property getters
|
|
151
|
-
|
|
152
|
-
/** Maximum file size in bytes */
|
|
153
|
-
readonly maxFileSize: number;
|
|
154
|
-
|
|
155
|
-
/** Maximum total extraction size in bytes */
|
|
156
|
-
readonly maxTotalSize: number;
|
|
157
|
-
|
|
158
|
-
/** Maximum compression ratio */
|
|
159
|
-
readonly maxCompressionRatio: number;
|
|
160
|
-
|
|
161
|
-
/** Maximum number of files */
|
|
162
|
-
readonly maxFileCount: number;
|
|
163
|
-
|
|
164
|
-
/** Maximum path depth */
|
|
165
|
-
readonly maxPathDepth: number;
|
|
166
|
-
|
|
167
|
-
/** Whether file permissions are preserved from archive */
|
|
168
|
-
readonly preservePermissions: boolean;
|
|
169
|
-
|
|
170
|
-
/** Whether symlinks are allowed */
|
|
171
|
-
readonly allowSymlinks: boolean;
|
|
172
|
-
|
|
173
|
-
/** Whether hardlinks are allowed */
|
|
174
|
-
readonly allowHardlinks: boolean;
|
|
175
|
-
|
|
176
|
-
/** Whether absolute paths are allowed */
|
|
177
|
-
readonly allowAbsolutePaths: boolean;
|
|
178
|
-
|
|
179
|
-
/** Whether world-writable files are allowed */
|
|
180
|
-
readonly allowWorldWritable: boolean;
|
|
181
|
-
|
|
182
|
-
/** List of allowed file extensions */
|
|
183
|
-
readonly allowedExtensions: string[];
|
|
184
|
-
|
|
185
|
-
/** List of banned path components */
|
|
186
|
-
readonly bannedPathComponents: string[];
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Report of an archive extraction operation.
|
|
191
|
-
*
|
|
192
|
-
* Contains statistics and metadata about the extraction process.
|
|
193
|
-
*/
|
|
194
|
-
export interface ExtractionReport {
|
|
195
|
-
/** Number of files successfully extracted */
|
|
196
|
-
filesExtracted: number;
|
|
197
|
-
|
|
198
|
-
/** Number of directories created */
|
|
199
|
-
directoriesCreated: number;
|
|
200
|
-
|
|
201
|
-
/** Number of symlinks created */
|
|
202
|
-
symlinksCreated: number;
|
|
203
|
-
|
|
204
|
-
/** Total bytes written to disk */
|
|
205
|
-
bytesWritten: number;
|
|
206
|
-
|
|
207
|
-
/** Extraction duration in milliseconds */
|
|
208
|
-
durationMs: number;
|
|
209
|
-
|
|
210
|
-
/** Number of files skipped due to security checks */
|
|
211
|
-
filesSkipped: number;
|
|
212
|
-
|
|
213
|
-
/** List of warning messages */
|
|
214
|
-
warnings: string[];
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Extract an archive to the specified directory (async).
|
|
219
|
-
*
|
|
220
|
-
* This function provides secure archive extraction with configurable
|
|
221
|
-
* security policies. By default, it uses a restrictive security
|
|
222
|
-
* configuration that blocks symlinks, hardlinks, absolute paths, and
|
|
223
|
-
* enforces resource quotas.
|
|
224
|
-
*
|
|
225
|
-
* Error codes in exception messages:
|
|
226
|
-
* - `PATH_TRAVERSAL`: Path traversal attempt detected
|
|
227
|
-
* - `SYMLINK_ESCAPE`: Symlink points outside extraction directory
|
|
228
|
-
* - `HARDLINK_ESCAPE`: Hardlink target outside extraction directory
|
|
229
|
-
* - `ZIP_BOMB`: Potential zip bomb detected
|
|
230
|
-
* - `INVALID_PERMISSIONS`: File permissions are invalid or unsafe
|
|
231
|
-
* - `QUOTA_EXCEEDED`: Resource quota exceeded
|
|
232
|
-
* - `SECURITY_VIOLATION`: Security policy violation
|
|
233
|
-
* - `UNSUPPORTED_FORMAT`: Archive format not supported
|
|
234
|
-
* - `INVALID_ARCHIVE`: Archive is corrupted
|
|
235
|
-
* - `IO_ERROR`: I/O operation failed
|
|
236
|
-
*
|
|
237
|
-
* @param archivePath - Path to the archive file
|
|
238
|
-
* @param outputDir - Directory where files will be extracted
|
|
239
|
-
* @param config - Optional SecurityConfig (uses secure defaults if omitted)
|
|
240
|
-
* @returns Promise resolving to ExtractionReport with extraction statistics
|
|
241
|
-
* @throws Error for security violations or I/O errors
|
|
242
|
-
*
|
|
243
|
-
* @example
|
|
244
|
-
* ```typescript
|
|
245
|
-
* // Use secure defaults
|
|
246
|
-
* const report = await extractArchive('archive.tar.gz', '/tmp/output');
|
|
247
|
-
* console.log(`Extracted ${report.filesExtracted} files`);
|
|
248
|
-
*
|
|
249
|
-
* // Customize security settings
|
|
250
|
-
* const config = new SecurityConfig().maxFileSize(100 * 1024 * 1024);
|
|
251
|
-
* const report = await extractArchive('archive.tar.gz', '/tmp/output', config);
|
|
252
|
-
* ```
|
|
253
|
-
*/
|
|
254
|
-
export function extractArchive(
|
|
255
|
-
archivePath: string,
|
|
256
|
-
outputDir: string,
|
|
257
|
-
config?: SecurityConfig
|
|
258
|
-
): Promise<ExtractionReport>;
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Extract an archive to the specified directory (sync).
|
|
262
|
-
*
|
|
263
|
-
* Synchronous version of extractArchive. Blocks the event loop until
|
|
264
|
-
* extraction completes. Prefer the async version for most use cases.
|
|
265
|
-
*
|
|
266
|
-
* @param archivePath - Path to the archive file
|
|
267
|
-
* @param outputDir - Directory where files will be extracted
|
|
268
|
-
* @param config - Optional SecurityConfig (uses secure defaults if omitted)
|
|
269
|
-
* @returns ExtractionReport with extraction statistics
|
|
270
|
-
* @throws Error for security violations or I/O errors
|
|
271
|
-
*
|
|
272
|
-
* @example
|
|
273
|
-
* ```typescript
|
|
274
|
-
* // Use secure defaults
|
|
275
|
-
* const report = extractArchiveSync('archive.tar.gz', '/tmp/output');
|
|
276
|
-
* console.log(`Extracted ${report.filesExtracted} files`);
|
|
277
|
-
*
|
|
278
|
-
* // Customize security settings
|
|
279
|
-
* const config = new SecurityConfig().maxFileSize(100 * 1024 * 1024);
|
|
280
|
-
* const report = extractArchiveSync('archive.tar.gz', '/tmp/output', config);
|
|
281
|
-
* ```
|
|
282
|
-
*/
|
|
283
|
-
export function extractArchiveSync(
|
|
284
|
-
archivePath: string,
|
|
285
|
-
outputDir: string,
|
|
286
|
-
config?: SecurityConfig
|
|
287
|
-
): ExtractionReport;
|