file-entry-cache 11.0.0-beta.1 → 11.0.0-beta.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/README.md +218 -51
- package/dist/index.cjs +86 -8
- package/dist/index.d.cts +77 -6
- package/dist/index.d.ts +77 -6
- package/dist/index.js +86 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
- Ideal for processes that work on a specific set of files
|
|
16
16
|
- Persists cache to Disk via `reconcile()` or `persistInterval` on `cache` options.
|
|
17
17
|
- Uses `checksum` to determine if a file has changed
|
|
18
|
-
- Supports `relative` and `absolute` paths
|
|
18
|
+
- Supports `relative` and `absolute` paths with configurable current working directory
|
|
19
19
|
- Portable cache files when using relative paths
|
|
20
20
|
- ESM and CommonJS support with Typescript
|
|
21
21
|
|
|
@@ -23,11 +23,17 @@
|
|
|
23
23
|
|
|
24
24
|
- [Installation](#installation)
|
|
25
25
|
- [Getting Started](#getting-started)
|
|
26
|
+
- [Changes from v10 to v11](#changes-from-v10-to-v11)
|
|
26
27
|
- [Changes from v9 to v10](#changes-from-v9-to-v10)
|
|
27
28
|
- [Global Default Functions](#global-default-functions)
|
|
28
29
|
- [FileEntryCache Options (FileEntryCacheOptions)](#fileentrycache-options-fileentrycacheoptions)
|
|
29
30
|
- [API](#api)
|
|
30
31
|
- [Get File Descriptor](#get-file-descriptor)
|
|
32
|
+
- [Path Handling and Current Working Directory](#path-handling-and-current-working-directory)
|
|
33
|
+
- [Cache Portability](#cache-portability)
|
|
34
|
+
- [Maximum Portability with Checksums](#maximum-portability-with-checksums)
|
|
35
|
+
- [Handling Project Relocations](#handling-project-relocations)
|
|
36
|
+
- [Path Security and Traversal Prevention](#path-security-and-traversal-prevention)
|
|
31
37
|
- [Using Checksums to Determine if a File has Changed (useCheckSum)](#using-checksums-to-determine-if-a-file-has-changed-usechecksum)
|
|
32
38
|
- [Setting Additional Meta Data](#setting-additional-meta-data)
|
|
33
39
|
- [How to Contribute](#how-to-contribute)
|
|
@@ -78,41 +84,16 @@ let fileDescriptor = cache.getFileDescriptor('./src/file.txt');
|
|
|
78
84
|
console.log(fileDescriptor.changed); // false as it has not changed from the saved cache.
|
|
79
85
|
```
|
|
80
86
|
|
|
81
|
-
## Migration Guide from v10 to v11
|
|
82
|
-
|
|
83
|
-
The main breaking change is the removal of `currentWorkingDirectory`. Here's how to update your code:
|
|
84
|
-
|
|
85
|
-
**Before (v10):**
|
|
86
|
-
```javascript
|
|
87
|
-
const cache = new FileEntryCache({
|
|
88
|
-
currentWorkingDirectory: '/project/root'
|
|
89
|
-
});
|
|
90
|
-
// This would store the key as 'src/file.js'
|
|
91
|
-
cache.getFileDescriptor('/project/root/src/file.js');
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
**After (v11):**
|
|
95
|
-
```javascript
|
|
96
|
-
const cache = new FileEntryCache();
|
|
97
|
-
// Now stores the key exactly as provided
|
|
98
|
-
cache.getFileDescriptor('./src/file.js'); // Key: './src/file.js'
|
|
99
|
-
cache.getFileDescriptor('/project/root/src/file.js'); // Key: '/project/root/src/file.js'
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
If you were using absolute paths with `currentWorkingDirectory`, you'll need to update your code to use relative paths if you want portable cache files.
|
|
103
87
|
|
|
104
88
|
# Changes from v10 to v11
|
|
105
89
|
|
|
106
90
|
**BREAKING CHANGES:**
|
|
107
|
-
-
|
|
108
|
-
- **Path handling changes** - The cache now stores paths exactly as they are provided:
|
|
109
|
-
- Relative paths remain relative in the cache
|
|
110
|
-
- Absolute paths remain absolute in the cache
|
|
111
|
-
- The same file accessed with different path formats will create separate cache entries
|
|
112
|
-
- **Renamed method** - `renameAbsolutePathKeys()` is now `renameCacheKeys()` to reflect that it works with any path format
|
|
113
|
-
- **Simplified API** - Removed `currentWorkingDirectory` parameter from all methods including `getFileDescriptor()`, `removeEntry()`, and factory functions
|
|
91
|
+
- **`strictPaths` now defaults to `true`** - Path traversal protection is enabled by default for security. To restore v10 behavior, explicitly set `strictPaths: false`
|
|
114
92
|
|
|
115
|
-
|
|
93
|
+
**NEW FEATURES:**
|
|
94
|
+
- **Added `cwd` option** - You can now specify a custom current working directory for resolving relative paths
|
|
95
|
+
- **Added `strictPaths` option** - Provides protection against path traversal attacks (enabled by default)
|
|
96
|
+
- **Improved cache portability** - When using relative paths with the same `cwd`, cache files are portable across different environments
|
|
116
97
|
|
|
117
98
|
# Changes from v9 to v10
|
|
118
99
|
|
|
@@ -127,13 +108,15 @@ There have been many features added and changes made to the `file-entry-cache` c
|
|
|
127
108
|
- On `FileEntryDescriptor.meta` if using typescript you need to use the `meta.data` to set additional information. This is to allow for better type checking and to avoid conflicts with the `meta` object which was `any`.
|
|
128
109
|
|
|
129
110
|
# Global Default Functions
|
|
130
|
-
- `create(cacheId: string, cacheDirectory?: string, useCheckSum?: boolean)` - Creates a new instance of the `FileEntryCache` class
|
|
131
|
-
- `createFromFile(cachePath: string, useCheckSum?: boolean)` - Creates a new instance of the `FileEntryCache` class and loads the cache from a file.
|
|
111
|
+
- `create(cacheId: string, cacheDirectory?: string, useCheckSum?: boolean, cwd?: string)` - Creates a new instance of the `FileEntryCache` class
|
|
112
|
+
- `createFromFile(cachePath: string, useCheckSum?: boolean, cwd?: string)` - Creates a new instance of the `FileEntryCache` class and loads the cache from a file.
|
|
132
113
|
|
|
133
114
|
# FileEntryCache Options (FileEntryCacheOptions)
|
|
134
115
|
- `useModifiedTime?` - If `true` it will use the modified time to determine if the file has changed. Default is `true`
|
|
135
116
|
- `useCheckSum?` - If `true` it will use a checksum to determine if the file has changed. Default is `false`
|
|
136
117
|
- `hashAlgorithm?` - The algorithm to use for the checksum. Default is `md5` but can be any algorithm supported by `crypto.createHash`
|
|
118
|
+
- `cwd?` - The current working directory for resolving relative paths. Default is `process.cwd()`
|
|
119
|
+
- `strictPaths?` - If `true` restricts file access to within `cwd` boundaries, preventing path traversal attacks. Default is `true`
|
|
137
120
|
- `cache.ttl?` - The time to live for the cache in milliseconds. Default is `0` which means no expiration
|
|
138
121
|
- `cache.lruSize?` - The number of items to keep in the cache. Default is `0` which means no limit
|
|
139
122
|
- `cache.useClone?` - If `true` it will clone the data before returning it. Default is `false`
|
|
@@ -150,17 +133,21 @@ There have been many features added and changes made to the `file-entry-cache` c
|
|
|
150
133
|
- `useCheckSum: boolean` - If `true` it will use a checksum to determine if the file has changed. Default is `false`
|
|
151
134
|
- `hashAlgorithm: string` - The algorithm to use for the checksum. Default is `md5` but can be any algorithm supported by `crypto.createHash`
|
|
152
135
|
- `getHash(buffer: Buffer): string` - Gets the hash of a buffer used for checksums
|
|
136
|
+
- `cwd: string` - The current working directory for resolving relative paths. Default is `process.cwd()`
|
|
137
|
+
- `strictPaths: boolean` - If `true` restricts file access to within `cwd` boundaries. Default is `true`
|
|
153
138
|
- `createFileKey(filePath: string): string` - Returns the cache key for the file path (returns the path exactly as provided).
|
|
154
139
|
- `deleteCacheFile(): boolean` - Deletes the cache file from disk
|
|
155
140
|
- `destroy(): void` - Destroys the cache. This will clear the cache in memory. If using cache persistence it will stop the interval.
|
|
156
|
-
- `removeEntry(filePath: string): void` - Removes an entry from the cache
|
|
141
|
+
- `removeEntry(filePath: string): void` - Removes an entry from the cache.
|
|
157
142
|
- `reconcile(): void` - Saves the cache to disk and removes any files that are no longer found.
|
|
158
143
|
- `hasFileChanged(filePath: string): boolean` - Checks if the file has changed. This will return `true` if the file has changed.
|
|
159
144
|
- `getFileDescriptor(filePath: string, options?: { useModifiedTime?: boolean, useCheckSum?: boolean }): FileEntryDescriptor` - Gets the file descriptor for the file. Please refer to the entire section on `Get File Descriptor` for more information.
|
|
160
|
-
- `normalizeEntries(
|
|
145
|
+
- `normalizeEntries(files?: string[]): FileDescriptor[]` - Normalizes the entries. If no files are provided, it will return all cached entries.
|
|
161
146
|
- `analyzeFiles(files: string[])` will return `AnalyzedFiles` object with `changedFiles`, `notFoundFiles`, and `notChangedFiles` as FileDescriptor arrays.
|
|
162
147
|
- `getUpdatedFiles(files: string[])` will return an array of `FileEntryDescriptor` objects that have changed.
|
|
163
148
|
- `getFileDescriptorsByPath(filePath: string): FileEntryDescriptor[]` will return an array of `FileEntryDescriptor` objects that starts with the path prefix specified.
|
|
149
|
+
- `getAbsolutePath(filePath: string): string` - Resolves a relative path to absolute using the configured `cwd`. Returns absolute paths unchanged. When `strictPaths` is enabled, throws an error if the path resolves outside `cwd`.
|
|
150
|
+
- `getAbsolutePathWithCwd(filePath: string, cwd: string): string` - Resolves a relative path to absolute using a custom working directory. When `strictPaths` is enabled, throws an error if the path resolves outside the provided `cwd`.
|
|
164
151
|
|
|
165
152
|
# Get File Descriptor
|
|
166
153
|
|
|
@@ -172,32 +159,94 @@ The `getFileDescriptor(filePath: string, options?: { useCheckSum?: boolean, useM
|
|
|
172
159
|
- `meta: FileEntryMeta` - The meta data for the file. This has the following properties: `size`, `mtime`, `hash`, `data`. Note that `data` is an object that can be used to store additional information.
|
|
173
160
|
- `err` - If there was an error analyzing the file.
|
|
174
161
|
|
|
175
|
-
## Path Handling
|
|
162
|
+
## Path Handling and Current Working Directory
|
|
163
|
+
|
|
164
|
+
The cache stores paths exactly as they are provided (relative or absolute). When checking if files have changed, relative paths are resolved using the configured `cwd` (current working directory):
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
// Default: uses process.cwd()
|
|
168
|
+
const cache1 = fileEntryCache.create('cache1');
|
|
169
|
+
|
|
170
|
+
// Custom working directory
|
|
171
|
+
const cache2 = fileEntryCache.create('cache2', './cache', false, '/project/root');
|
|
172
|
+
// Or with options object
|
|
173
|
+
const cache3 = new FileEntryCache({ cwd: '/project/root' });
|
|
174
|
+
|
|
175
|
+
// The cache key is always the provided path
|
|
176
|
+
const descriptor = cache2.getFileDescriptor('./src/file.txt');
|
|
177
|
+
console.log(descriptor.key); // './src/file.txt'
|
|
178
|
+
// But file operations resolve from: '/project/root/src/file.txt'
|
|
179
|
+
```
|
|
176
180
|
|
|
177
|
-
|
|
181
|
+
### Cache Portability
|
|
178
182
|
|
|
179
|
-
|
|
180
|
-
- **Absolute paths** remain absolute in the cache
|
|
181
|
-
- The same file accessed with different path formats creates **separate cache entries**
|
|
183
|
+
Using relative paths with a consistent `cwd` (defaults to `process.cwd()`) makes cache files portable across different machines and environments. This is especially useful for CI/CD pipelines and team development.
|
|
182
184
|
|
|
183
185
|
```javascript
|
|
184
|
-
|
|
186
|
+
// On machine A (project at /home/user/project)
|
|
187
|
+
const cacheA = fileEntryCache.create('build-cache', './cache', false, '/home/user/project');
|
|
188
|
+
cacheA.getFileDescriptor('./src/index.js'); // Resolves to /home/user/project/src/index.js
|
|
189
|
+
cacheA.reconcile();
|
|
190
|
+
|
|
191
|
+
// On machine B (project at /workspace/project)
|
|
192
|
+
const cacheB = fileEntryCache.create('build-cache', './cache', false, '/workspace/project');
|
|
193
|
+
cacheB.getFileDescriptor('./src/index.js'); // Resolves to /workspace/project/src/index.js
|
|
194
|
+
// Cache hit! File hasn't changed since machine A
|
|
195
|
+
```
|
|
185
196
|
|
|
186
|
-
|
|
187
|
-
const relativeDescriptor = fileEntryCache.getFileDescriptor('./file.txt');
|
|
188
|
-
console.log(relativeDescriptor.key); // './file.txt'
|
|
197
|
+
### Maximum Portability with Checksums
|
|
189
198
|
|
|
190
|
-
|
|
191
|
-
const absolutePath = path.resolve('./file.txt');
|
|
192
|
-
const absoluteDescriptor = fileEntryCache.getFileDescriptor(absolutePath);
|
|
193
|
-
console.log(absoluteDescriptor.key); // '/full/path/to/file.txt'
|
|
199
|
+
For maximum cache portability across different environments, use checksums (`useCheckSum: true`) along with relative paths and `cwd` which defaults to `process.cwd()`. This ensures that cache validity is determined by file content rather than modification times, which can vary across systems:
|
|
194
200
|
|
|
195
|
-
|
|
201
|
+
```javascript
|
|
202
|
+
// Development machine
|
|
203
|
+
const devCache = fileEntryCache.create(
|
|
204
|
+
'.buildcache',
|
|
205
|
+
'./cache', // cache directory
|
|
206
|
+
true // Use checksums for content-based comparison
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
// Process files using relative paths
|
|
210
|
+
const descriptor = devCache.getFileDescriptor('./src/index.js');
|
|
211
|
+
if (descriptor.changed) {
|
|
212
|
+
console.log('Building ./src/index.js...');
|
|
213
|
+
// Build process here
|
|
214
|
+
}
|
|
215
|
+
devCache.reconcile(); // Save cache
|
|
216
|
+
|
|
217
|
+
// CI/CD Pipeline or another developer's machine
|
|
218
|
+
const ciCache = fileEntryCache.create(
|
|
219
|
+
'.buildcache',
|
|
220
|
+
'./node_modules/.cache',
|
|
221
|
+
true, // Same checksum setting
|
|
222
|
+
process.cwd() // Different absolute path, same relative structure
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
// Same relative path works across environments
|
|
226
|
+
const descriptor2 = ciCache.getFileDescriptor('./src/index.js');
|
|
227
|
+
if (!descriptor2.changed) {
|
|
228
|
+
console.log('Using cached result for ./src/index.js');
|
|
229
|
+
// Skip rebuild - file content unchanged
|
|
230
|
+
}
|
|
196
231
|
```
|
|
197
232
|
|
|
198
|
-
|
|
233
|
+
### Handling Project Relocations
|
|
234
|
+
|
|
235
|
+
Cache remains valid even when projects are moved or renamed:
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
// Original location: /projects/my-app
|
|
239
|
+
const cache1 = fileEntryCache.create('.cache', './cache', true, '/projects/my-app');
|
|
240
|
+
cache1.getFileDescriptor('./src/app.js');
|
|
241
|
+
cache1.reconcile();
|
|
242
|
+
|
|
243
|
+
// After moving project to: /archived/2024/my-app
|
|
244
|
+
const cache2 = fileEntryCache.create('.cache', './cache', true, '/archived/2024/my-app');
|
|
245
|
+
cache2.getFileDescriptor('./src/app.js'); // Still finds cached entry!
|
|
246
|
+
// Cache valid as long as relative structure unchanged
|
|
247
|
+
```
|
|
199
248
|
|
|
200
|
-
If there is an error when trying to get the file descriptor it will return
|
|
249
|
+
If there is an error when trying to get the file descriptor it will return a `notFound` and `err` property with the error.
|
|
201
250
|
|
|
202
251
|
```javascript
|
|
203
252
|
const fileEntryCache = new FileEntryCache();
|
|
@@ -211,6 +260,124 @@ if (fileDescriptor.notFound) {
|
|
|
211
260
|
}
|
|
212
261
|
```
|
|
213
262
|
|
|
263
|
+
# Path Security and Traversal Prevention
|
|
264
|
+
|
|
265
|
+
The `strictPaths` option provides security against path traversal attacks by restricting file access to within the configured `cwd` boundaries. **This is enabled by default (since v11)** to ensure secure defaults when processing untrusted input or when running in security-sensitive environments.
|
|
266
|
+
|
|
267
|
+
## Basic Usage
|
|
268
|
+
|
|
269
|
+
```javascript
|
|
270
|
+
// strictPaths is enabled by default for security
|
|
271
|
+
const cache = new FileEntryCache({
|
|
272
|
+
cwd: '/project/root'
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// This will work - file is within cwd
|
|
276
|
+
const descriptor = cache.getFileDescriptor('./src/index.js');
|
|
277
|
+
|
|
278
|
+
// This will throw an error - attempts to access parent directory
|
|
279
|
+
try {
|
|
280
|
+
cache.getFileDescriptor('../../../etc/passwd');
|
|
281
|
+
} catch (error) {
|
|
282
|
+
console.error(error); // Path traversal attempt blocked
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// To allow parent directory access (not recommended for untrusted input)
|
|
286
|
+
const unsafeCache = new FileEntryCache({
|
|
287
|
+
cwd: '/project/root',
|
|
288
|
+
strictPaths: false // Explicitly disable protection
|
|
289
|
+
});
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Security Features
|
|
293
|
+
|
|
294
|
+
When `strictPaths` is enabled:
|
|
295
|
+
- **Path Traversal Prevention**: Blocks attempts to access files outside the working directory using `../` sequences
|
|
296
|
+
- **Null Byte Protection**: Automatically removes null bytes from paths to prevent injection attacks
|
|
297
|
+
- **Path Normalization**: Cleans and normalizes paths to prevent bypass attempts
|
|
298
|
+
|
|
299
|
+
## Use Cases
|
|
300
|
+
|
|
301
|
+
### Build Tools with Untrusted Input
|
|
302
|
+
```javascript
|
|
303
|
+
// Secure build tool configuration
|
|
304
|
+
const cache = fileEntryCache.create(
|
|
305
|
+
'.buildcache',
|
|
306
|
+
'./cache',
|
|
307
|
+
true, // useCheckSum
|
|
308
|
+
process.cwd()
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
// Enable strict path checking for security
|
|
312
|
+
cache.strictPaths = true;
|
|
313
|
+
|
|
314
|
+
// Process user-provided file paths safely
|
|
315
|
+
function processUserFile(userProvidedPath) {
|
|
316
|
+
try {
|
|
317
|
+
const descriptor = cache.getFileDescriptor(userProvidedPath);
|
|
318
|
+
// Safe to process - file is within boundaries
|
|
319
|
+
return descriptor;
|
|
320
|
+
} catch (error) {
|
|
321
|
+
if (error.message.includes('Path traversal attempt blocked')) {
|
|
322
|
+
console.warn('Security: Blocked access to:', userProvidedPath);
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### CI/CD Environments
|
|
331
|
+
```javascript
|
|
332
|
+
// Strict security for CI/CD pipelines
|
|
333
|
+
const cache = new FileEntryCache({
|
|
334
|
+
cwd: process.env.GITHUB_WORKSPACE || process.cwd(),
|
|
335
|
+
strictPaths: true, // Prevent access outside workspace
|
|
336
|
+
useCheckSum: true // Content-based validation
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// All file operations are now restricted to the workspace
|
|
340
|
+
cache.getFileDescriptor('./src/app.js'); // ✓ Allowed
|
|
341
|
+
cache.getFileDescriptor('/etc/passwd'); // ✗ Blocked (absolute path outside cwd)
|
|
342
|
+
cache.getFileDescriptor('../../../root'); // ✗ Blocked (path traversal)
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Dynamic Security Control
|
|
346
|
+
```javascript
|
|
347
|
+
const cache = new FileEntryCache({ cwd: '/safe/directory' });
|
|
348
|
+
|
|
349
|
+
// Start with relaxed mode for trusted operations
|
|
350
|
+
cache.strictPaths = false;
|
|
351
|
+
processInternalFiles();
|
|
352
|
+
|
|
353
|
+
// Enable strict mode for untrusted input
|
|
354
|
+
cache.strictPaths = true;
|
|
355
|
+
processUserUploadedPaths();
|
|
356
|
+
|
|
357
|
+
// Return to relaxed mode if needed
|
|
358
|
+
cache.strictPaths = false;
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## Default Behavior
|
|
362
|
+
|
|
363
|
+
**As of v11, `strictPaths` is enabled by default** to provide secure defaults. This means:
|
|
364
|
+
- Path traversal attempts using `../` are blocked
|
|
365
|
+
- File access is restricted to within the configured `cwd`
|
|
366
|
+
- Null bytes in paths are automatically sanitized
|
|
367
|
+
|
|
368
|
+
### Migrating from v10 or Earlier
|
|
369
|
+
|
|
370
|
+
If you're upgrading from v10 or earlier and need to maintain the previous behavior (for example, if your code legitimately accesses parent directories), you can explicitly disable strict paths:
|
|
371
|
+
|
|
372
|
+
```javascript
|
|
373
|
+
const cache = new FileEntryCache({
|
|
374
|
+
cwd: process.cwd(),
|
|
375
|
+
strictPaths: false // Restore v10 behavior
|
|
376
|
+
});
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
However, we strongly recommend keeping `strictPaths: true` and adjusting your code to work within the security boundaries, especially when processing any untrusted input.
|
|
380
|
+
|
|
214
381
|
# Using Checksums to Determine if a File has Changed (useCheckSum)
|
|
215
382
|
|
|
216
383
|
By default the `useCheckSum` is `false`. This means that the `FileEntryCache` will use the `mtime` and `ctime` to determine if the file has changed. If you set `useCheckSum` to `true` it will use a checksum to determine if the file has changed. This is useful when you want to make sure that the file has not changed at all.
|
package/dist/index.cjs
CHANGED
|
@@ -40,14 +40,15 @@ var import_node_crypto = __toESM(require("crypto"), 1);
|
|
|
40
40
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
41
41
|
var import_node_path = __toESM(require("path"), 1);
|
|
42
42
|
var import_flat_cache = require("flat-cache");
|
|
43
|
-
function createFromFile(filePath, useCheckSum) {
|
|
43
|
+
function createFromFile(filePath, useCheckSum, cwd) {
|
|
44
44
|
const fname = import_node_path.default.basename(filePath);
|
|
45
45
|
const directory = import_node_path.default.dirname(filePath);
|
|
46
|
-
return create(fname, directory, useCheckSum);
|
|
46
|
+
return create(fname, directory, useCheckSum, cwd);
|
|
47
47
|
}
|
|
48
|
-
function create(cacheId, cacheDirectory, useCheckSum) {
|
|
48
|
+
function create(cacheId, cacheDirectory, useCheckSum, cwd) {
|
|
49
49
|
const options = {
|
|
50
50
|
useCheckSum,
|
|
51
|
+
cwd,
|
|
51
52
|
cache: {
|
|
52
53
|
cacheId,
|
|
53
54
|
cacheDir: cacheDirectory
|
|
@@ -71,9 +72,11 @@ var FileEntryCache = class {
|
|
|
71
72
|
_useCheckSum = false;
|
|
72
73
|
_useModifiedTime = true;
|
|
73
74
|
_hashAlgorithm = "md5";
|
|
75
|
+
_cwd = process.cwd();
|
|
76
|
+
_strictPaths = true;
|
|
74
77
|
/**
|
|
75
78
|
* Create a new FileEntryCache instance
|
|
76
|
-
* @param options - The options for the FileEntryCache
|
|
79
|
+
* @param options - The options for the FileEntryCache (all properties are optional with defaults)
|
|
77
80
|
*/
|
|
78
81
|
constructor(options) {
|
|
79
82
|
if (options?.cache) {
|
|
@@ -88,6 +91,12 @@ var FileEntryCache = class {
|
|
|
88
91
|
if (options?.hashAlgorithm) {
|
|
89
92
|
this._hashAlgorithm = options.hashAlgorithm;
|
|
90
93
|
}
|
|
94
|
+
if (options?.cwd) {
|
|
95
|
+
this._cwd = options.cwd;
|
|
96
|
+
}
|
|
97
|
+
if (options?.strictPaths !== void 0) {
|
|
98
|
+
this._strictPaths = options.strictPaths;
|
|
99
|
+
}
|
|
91
100
|
}
|
|
92
101
|
/**
|
|
93
102
|
* Get the cache
|
|
@@ -105,7 +114,7 @@ var FileEntryCache = class {
|
|
|
105
114
|
}
|
|
106
115
|
/**
|
|
107
116
|
* Use the hash to check if the file has changed
|
|
108
|
-
* @returns {boolean} if the hash is used to check if the file has changed
|
|
117
|
+
* @returns {boolean} if the hash is used to check if the file has changed (default: false)
|
|
109
118
|
*/
|
|
110
119
|
get useCheckSum() {
|
|
111
120
|
return this._useCheckSum;
|
|
@@ -119,7 +128,7 @@ var FileEntryCache = class {
|
|
|
119
128
|
}
|
|
120
129
|
/**
|
|
121
130
|
* Use the modified time to check if the file has changed
|
|
122
|
-
* @returns {boolean} if the modified time is used to check if the file has changed
|
|
131
|
+
* @returns {boolean} if the modified time is used to check if the file has changed (default: true)
|
|
123
132
|
*/
|
|
124
133
|
get useModifiedTime() {
|
|
125
134
|
return this._useModifiedTime;
|
|
@@ -133,7 +142,7 @@ var FileEntryCache = class {
|
|
|
133
142
|
}
|
|
134
143
|
/**
|
|
135
144
|
* Get the hash algorithm
|
|
136
|
-
* @returns {string} The hash algorithm
|
|
145
|
+
* @returns {string} The hash algorithm (default: 'md5')
|
|
137
146
|
*/
|
|
138
147
|
get hashAlgorithm() {
|
|
139
148
|
return this._hashAlgorithm;
|
|
@@ -145,6 +154,34 @@ var FileEntryCache = class {
|
|
|
145
154
|
set hashAlgorithm(value) {
|
|
146
155
|
this._hashAlgorithm = value;
|
|
147
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* Get the current working directory
|
|
159
|
+
* @returns {string} The current working directory (default: process.cwd())
|
|
160
|
+
*/
|
|
161
|
+
get cwd() {
|
|
162
|
+
return this._cwd;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Set the current working directory
|
|
166
|
+
* @param {string} value - The value to set
|
|
167
|
+
*/
|
|
168
|
+
set cwd(value) {
|
|
169
|
+
this._cwd = value;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get whether to restrict paths to cwd boundaries
|
|
173
|
+
* @returns {boolean} Whether strict path checking is enabled (default: true)
|
|
174
|
+
*/
|
|
175
|
+
get strictPaths() {
|
|
176
|
+
return this._strictPaths;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Set whether to restrict paths to cwd boundaries
|
|
180
|
+
* @param {boolean} value - The value to set
|
|
181
|
+
*/
|
|
182
|
+
set strictPaths(value) {
|
|
183
|
+
this._strictPaths = value;
|
|
184
|
+
}
|
|
148
185
|
/**
|
|
149
186
|
* Given a buffer, calculate md5 hash of its content.
|
|
150
187
|
* @method getHash
|
|
@@ -369,13 +406,54 @@ var FileEntryCache = class {
|
|
|
369
406
|
}
|
|
370
407
|
/**
|
|
371
408
|
* Get the Absolute Path. If it is already absolute it will return the path as is.
|
|
409
|
+
* When strictPaths is enabled, ensures the resolved path stays within cwd boundaries.
|
|
372
410
|
* @method getAbsolutePath
|
|
373
411
|
* @param filePath - The file path to get the absolute path for
|
|
374
412
|
* @returns {string}
|
|
413
|
+
* @throws {Error} When strictPaths is true and path would resolve outside cwd
|
|
375
414
|
*/
|
|
376
415
|
getAbsolutePath(filePath) {
|
|
377
416
|
if (this.isRelativePath(filePath)) {
|
|
378
|
-
|
|
417
|
+
const sanitizedPath = filePath.replace(/\0/g, "");
|
|
418
|
+
const resolved = import_node_path.default.resolve(this._cwd, sanitizedPath);
|
|
419
|
+
if (this._strictPaths) {
|
|
420
|
+
const normalizedResolved = import_node_path.default.normalize(resolved);
|
|
421
|
+
const normalizedCwd = import_node_path.default.normalize(this._cwd);
|
|
422
|
+
const isWithinCwd = normalizedResolved === normalizedCwd || normalizedResolved.startsWith(normalizedCwd + import_node_path.default.sep);
|
|
423
|
+
if (!isWithinCwd) {
|
|
424
|
+
throw new Error(
|
|
425
|
+
`Path traversal attempt blocked: "${filePath}" resolves outside of working directory "${this._cwd}"`
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return resolved;
|
|
430
|
+
}
|
|
431
|
+
return filePath;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Get the Absolute Path with a custom working directory. If it is already absolute it will return the path as is.
|
|
435
|
+
* When strictPaths is enabled, ensures the resolved path stays within the provided cwd boundaries.
|
|
436
|
+
* @method getAbsolutePathWithCwd
|
|
437
|
+
* @param filePath - The file path to get the absolute path for
|
|
438
|
+
* @param cwd - The custom working directory to resolve relative paths from
|
|
439
|
+
* @returns {string}
|
|
440
|
+
* @throws {Error} When strictPaths is true and path would resolve outside the provided cwd
|
|
441
|
+
*/
|
|
442
|
+
getAbsolutePathWithCwd(filePath, cwd) {
|
|
443
|
+
if (this.isRelativePath(filePath)) {
|
|
444
|
+
const sanitizedPath = filePath.replace(/\0/g, "");
|
|
445
|
+
const resolved = import_node_path.default.resolve(cwd, sanitizedPath);
|
|
446
|
+
if (this._strictPaths) {
|
|
447
|
+
const normalizedResolved = import_node_path.default.normalize(resolved);
|
|
448
|
+
const normalizedCwd = import_node_path.default.normalize(cwd);
|
|
449
|
+
const isWithinCwd = normalizedResolved === normalizedCwd || normalizedResolved.startsWith(normalizedCwd + import_node_path.default.sep);
|
|
450
|
+
if (!isWithinCwd) {
|
|
451
|
+
throw new Error(
|
|
452
|
+
`Path traversal attempt blocked: "${filePath}" resolves outside of working directory "${cwd}"`
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return resolved;
|
|
379
457
|
}
|
|
380
458
|
return filePath;
|
|
381
459
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -2,35 +2,72 @@ import { Buffer } from 'node:buffer';
|
|
|
2
2
|
import { FlatCacheOptions, FlatCache } from 'flat-cache';
|
|
3
3
|
|
|
4
4
|
type FileEntryCacheOptions = {
|
|
5
|
+
/** Whether to use file modified time for change detection (default: true) */
|
|
5
6
|
useModifiedTime?: boolean;
|
|
7
|
+
/** Whether to use checksum for change detection (default: false) */
|
|
6
8
|
useCheckSum?: boolean;
|
|
9
|
+
/** Hash algorithm to use for checksum (default: 'md5') */
|
|
7
10
|
hashAlgorithm?: string;
|
|
11
|
+
/** Current working directory for resolving relative paths (default: process.cwd()) */
|
|
12
|
+
cwd?: string;
|
|
13
|
+
/** Restrict file access to within cwd boundaries (default: true) */
|
|
14
|
+
strictPaths?: boolean;
|
|
15
|
+
/** Options for the underlying flat cache */
|
|
8
16
|
cache?: FlatCacheOptions;
|
|
9
17
|
};
|
|
10
18
|
type GetFileDescriptorOptions = {
|
|
19
|
+
/** Whether to use checksum for this specific file check (overrides instance setting) */
|
|
11
20
|
useCheckSum?: boolean;
|
|
21
|
+
/** Whether to use modified time for this specific file check (overrides instance setting) */
|
|
12
22
|
useModifiedTime?: boolean;
|
|
13
23
|
};
|
|
14
24
|
type FileDescriptor = {
|
|
25
|
+
/** The cache key for this file (typically the file path) */
|
|
15
26
|
key: string;
|
|
27
|
+
/** Whether the file has changed since last cache check */
|
|
16
28
|
changed?: boolean;
|
|
29
|
+
/** Metadata about the file */
|
|
17
30
|
meta: FileDescriptorMeta;
|
|
31
|
+
/** Whether the file was not found */
|
|
18
32
|
notFound?: boolean;
|
|
33
|
+
/** Error encountered when accessing the file */
|
|
19
34
|
err?: Error;
|
|
20
35
|
};
|
|
21
36
|
type FileDescriptorMeta = {
|
|
37
|
+
/** File size in bytes */
|
|
22
38
|
size?: number;
|
|
39
|
+
/** File modification time (timestamp in milliseconds) */
|
|
23
40
|
mtime?: number;
|
|
41
|
+
/** File content hash (when useCheckSum is enabled) */
|
|
24
42
|
hash?: string;
|
|
43
|
+
/** Custom data associated with the file (e.g., lint results, metadata) */
|
|
25
44
|
data?: unknown;
|
|
26
45
|
};
|
|
27
46
|
type AnalyzedFiles = {
|
|
47
|
+
/** Array of file paths that have changed since last cache */
|
|
28
48
|
changedFiles: string[];
|
|
49
|
+
/** Array of file paths that were not found */
|
|
29
50
|
notFoundFiles: string[];
|
|
51
|
+
/** Array of file paths that have not changed since last cache */
|
|
30
52
|
notChangedFiles: string[];
|
|
31
53
|
};
|
|
32
|
-
|
|
33
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Create a new FileEntryCache instance from a file path
|
|
56
|
+
* @param filePath - The path to the cache file
|
|
57
|
+
* @param useCheckSum - Whether to use checksum to detect file changes (default: false)
|
|
58
|
+
* @param cwd - The current working directory for resolving relative paths (default: process.cwd())
|
|
59
|
+
* @returns A new FileEntryCache instance
|
|
60
|
+
*/
|
|
61
|
+
declare function createFromFile(filePath: string, useCheckSum?: boolean, cwd?: string): FileEntryCache;
|
|
62
|
+
/**
|
|
63
|
+
* Create a new FileEntryCache instance
|
|
64
|
+
* @param cacheId - The cache file name
|
|
65
|
+
* @param cacheDirectory - The directory to store the cache file (default: undefined, cache won't be persisted)
|
|
66
|
+
* @param useCheckSum - Whether to use checksum to detect file changes (default: false)
|
|
67
|
+
* @param cwd - The current working directory for resolving relative paths (default: process.cwd())
|
|
68
|
+
* @returns A new FileEntryCache instance
|
|
69
|
+
*/
|
|
70
|
+
declare function create(cacheId: string, cacheDirectory?: string, useCheckSum?: boolean, cwd?: string): FileEntryCache;
|
|
34
71
|
declare class FileEntryDefault {
|
|
35
72
|
static create: typeof create;
|
|
36
73
|
static createFromFile: typeof createFromFile;
|
|
@@ -40,9 +77,11 @@ declare class FileEntryCache {
|
|
|
40
77
|
private _useCheckSum;
|
|
41
78
|
private _useModifiedTime;
|
|
42
79
|
private _hashAlgorithm;
|
|
80
|
+
private _cwd;
|
|
81
|
+
private _strictPaths;
|
|
43
82
|
/**
|
|
44
83
|
* Create a new FileEntryCache instance
|
|
45
|
-
* @param options - The options for the FileEntryCache
|
|
84
|
+
* @param options - The options for the FileEntryCache (all properties are optional with defaults)
|
|
46
85
|
*/
|
|
47
86
|
constructor(options?: FileEntryCacheOptions);
|
|
48
87
|
/**
|
|
@@ -57,7 +96,7 @@ declare class FileEntryCache {
|
|
|
57
96
|
set cache(cache: FlatCache);
|
|
58
97
|
/**
|
|
59
98
|
* Use the hash to check if the file has changed
|
|
60
|
-
* @returns {boolean} if the hash is used to check if the file has changed
|
|
99
|
+
* @returns {boolean} if the hash is used to check if the file has changed (default: false)
|
|
61
100
|
*/
|
|
62
101
|
get useCheckSum(): boolean;
|
|
63
102
|
/**
|
|
@@ -67,7 +106,7 @@ declare class FileEntryCache {
|
|
|
67
106
|
set useCheckSum(value: boolean);
|
|
68
107
|
/**
|
|
69
108
|
* Use the modified time to check if the file has changed
|
|
70
|
-
* @returns {boolean} if the modified time is used to check if the file has changed
|
|
109
|
+
* @returns {boolean} if the modified time is used to check if the file has changed (default: true)
|
|
71
110
|
*/
|
|
72
111
|
get useModifiedTime(): boolean;
|
|
73
112
|
/**
|
|
@@ -77,7 +116,7 @@ declare class FileEntryCache {
|
|
|
77
116
|
set useModifiedTime(value: boolean);
|
|
78
117
|
/**
|
|
79
118
|
* Get the hash algorithm
|
|
80
|
-
* @returns {string} The hash algorithm
|
|
119
|
+
* @returns {string} The hash algorithm (default: 'md5')
|
|
81
120
|
*/
|
|
82
121
|
get hashAlgorithm(): string;
|
|
83
122
|
/**
|
|
@@ -85,6 +124,26 @@ declare class FileEntryCache {
|
|
|
85
124
|
* @param {string} value - The value to set
|
|
86
125
|
*/
|
|
87
126
|
set hashAlgorithm(value: string);
|
|
127
|
+
/**
|
|
128
|
+
* Get the current working directory
|
|
129
|
+
* @returns {string} The current working directory (default: process.cwd())
|
|
130
|
+
*/
|
|
131
|
+
get cwd(): string;
|
|
132
|
+
/**
|
|
133
|
+
* Set the current working directory
|
|
134
|
+
* @param {string} value - The value to set
|
|
135
|
+
*/
|
|
136
|
+
set cwd(value: string);
|
|
137
|
+
/**
|
|
138
|
+
* Get whether to restrict paths to cwd boundaries
|
|
139
|
+
* @returns {boolean} Whether strict path checking is enabled (default: true)
|
|
140
|
+
*/
|
|
141
|
+
get strictPaths(): boolean;
|
|
142
|
+
/**
|
|
143
|
+
* Set whether to restrict paths to cwd boundaries
|
|
144
|
+
* @param {boolean} value - The value to set
|
|
145
|
+
*/
|
|
146
|
+
set strictPaths(value: boolean);
|
|
88
147
|
/**
|
|
89
148
|
* Given a buffer, calculate md5 hash of its content.
|
|
90
149
|
* @method getHash
|
|
@@ -173,11 +232,23 @@ declare class FileEntryCache {
|
|
|
173
232
|
getFileDescriptorsByPath(filePath: string): FileDescriptor[];
|
|
174
233
|
/**
|
|
175
234
|
* Get the Absolute Path. If it is already absolute it will return the path as is.
|
|
235
|
+
* When strictPaths is enabled, ensures the resolved path stays within cwd boundaries.
|
|
176
236
|
* @method getAbsolutePath
|
|
177
237
|
* @param filePath - The file path to get the absolute path for
|
|
178
238
|
* @returns {string}
|
|
239
|
+
* @throws {Error} When strictPaths is true and path would resolve outside cwd
|
|
179
240
|
*/
|
|
180
241
|
getAbsolutePath(filePath: string): string;
|
|
242
|
+
/**
|
|
243
|
+
* Get the Absolute Path with a custom working directory. If it is already absolute it will return the path as is.
|
|
244
|
+
* When strictPaths is enabled, ensures the resolved path stays within the provided cwd boundaries.
|
|
245
|
+
* @method getAbsolutePathWithCwd
|
|
246
|
+
* @param filePath - The file path to get the absolute path for
|
|
247
|
+
* @param cwd - The custom working directory to resolve relative paths from
|
|
248
|
+
* @returns {string}
|
|
249
|
+
* @throws {Error} When strictPaths is true and path would resolve outside the provided cwd
|
|
250
|
+
*/
|
|
251
|
+
getAbsolutePathWithCwd(filePath: string, cwd: string): string;
|
|
181
252
|
/**
|
|
182
253
|
* Rename cache keys that start with a given path prefix.
|
|
183
254
|
* @method renameCacheKeys
|
package/dist/index.d.ts
CHANGED
|
@@ -2,35 +2,72 @@ import { Buffer } from 'node:buffer';
|
|
|
2
2
|
import { FlatCacheOptions, FlatCache } from 'flat-cache';
|
|
3
3
|
|
|
4
4
|
type FileEntryCacheOptions = {
|
|
5
|
+
/** Whether to use file modified time for change detection (default: true) */
|
|
5
6
|
useModifiedTime?: boolean;
|
|
7
|
+
/** Whether to use checksum for change detection (default: false) */
|
|
6
8
|
useCheckSum?: boolean;
|
|
9
|
+
/** Hash algorithm to use for checksum (default: 'md5') */
|
|
7
10
|
hashAlgorithm?: string;
|
|
11
|
+
/** Current working directory for resolving relative paths (default: process.cwd()) */
|
|
12
|
+
cwd?: string;
|
|
13
|
+
/** Restrict file access to within cwd boundaries (default: true) */
|
|
14
|
+
strictPaths?: boolean;
|
|
15
|
+
/** Options for the underlying flat cache */
|
|
8
16
|
cache?: FlatCacheOptions;
|
|
9
17
|
};
|
|
10
18
|
type GetFileDescriptorOptions = {
|
|
19
|
+
/** Whether to use checksum for this specific file check (overrides instance setting) */
|
|
11
20
|
useCheckSum?: boolean;
|
|
21
|
+
/** Whether to use modified time for this specific file check (overrides instance setting) */
|
|
12
22
|
useModifiedTime?: boolean;
|
|
13
23
|
};
|
|
14
24
|
type FileDescriptor = {
|
|
25
|
+
/** The cache key for this file (typically the file path) */
|
|
15
26
|
key: string;
|
|
27
|
+
/** Whether the file has changed since last cache check */
|
|
16
28
|
changed?: boolean;
|
|
29
|
+
/** Metadata about the file */
|
|
17
30
|
meta: FileDescriptorMeta;
|
|
31
|
+
/** Whether the file was not found */
|
|
18
32
|
notFound?: boolean;
|
|
33
|
+
/** Error encountered when accessing the file */
|
|
19
34
|
err?: Error;
|
|
20
35
|
};
|
|
21
36
|
type FileDescriptorMeta = {
|
|
37
|
+
/** File size in bytes */
|
|
22
38
|
size?: number;
|
|
39
|
+
/** File modification time (timestamp in milliseconds) */
|
|
23
40
|
mtime?: number;
|
|
41
|
+
/** File content hash (when useCheckSum is enabled) */
|
|
24
42
|
hash?: string;
|
|
43
|
+
/** Custom data associated with the file (e.g., lint results, metadata) */
|
|
25
44
|
data?: unknown;
|
|
26
45
|
};
|
|
27
46
|
type AnalyzedFiles = {
|
|
47
|
+
/** Array of file paths that have changed since last cache */
|
|
28
48
|
changedFiles: string[];
|
|
49
|
+
/** Array of file paths that were not found */
|
|
29
50
|
notFoundFiles: string[];
|
|
51
|
+
/** Array of file paths that have not changed since last cache */
|
|
30
52
|
notChangedFiles: string[];
|
|
31
53
|
};
|
|
32
|
-
|
|
33
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Create a new FileEntryCache instance from a file path
|
|
56
|
+
* @param filePath - The path to the cache file
|
|
57
|
+
* @param useCheckSum - Whether to use checksum to detect file changes (default: false)
|
|
58
|
+
* @param cwd - The current working directory for resolving relative paths (default: process.cwd())
|
|
59
|
+
* @returns A new FileEntryCache instance
|
|
60
|
+
*/
|
|
61
|
+
declare function createFromFile(filePath: string, useCheckSum?: boolean, cwd?: string): FileEntryCache;
|
|
62
|
+
/**
|
|
63
|
+
* Create a new FileEntryCache instance
|
|
64
|
+
* @param cacheId - The cache file name
|
|
65
|
+
* @param cacheDirectory - The directory to store the cache file (default: undefined, cache won't be persisted)
|
|
66
|
+
* @param useCheckSum - Whether to use checksum to detect file changes (default: false)
|
|
67
|
+
* @param cwd - The current working directory for resolving relative paths (default: process.cwd())
|
|
68
|
+
* @returns A new FileEntryCache instance
|
|
69
|
+
*/
|
|
70
|
+
declare function create(cacheId: string, cacheDirectory?: string, useCheckSum?: boolean, cwd?: string): FileEntryCache;
|
|
34
71
|
declare class FileEntryDefault {
|
|
35
72
|
static create: typeof create;
|
|
36
73
|
static createFromFile: typeof createFromFile;
|
|
@@ -40,9 +77,11 @@ declare class FileEntryCache {
|
|
|
40
77
|
private _useCheckSum;
|
|
41
78
|
private _useModifiedTime;
|
|
42
79
|
private _hashAlgorithm;
|
|
80
|
+
private _cwd;
|
|
81
|
+
private _strictPaths;
|
|
43
82
|
/**
|
|
44
83
|
* Create a new FileEntryCache instance
|
|
45
|
-
* @param options - The options for the FileEntryCache
|
|
84
|
+
* @param options - The options for the FileEntryCache (all properties are optional with defaults)
|
|
46
85
|
*/
|
|
47
86
|
constructor(options?: FileEntryCacheOptions);
|
|
48
87
|
/**
|
|
@@ -57,7 +96,7 @@ declare class FileEntryCache {
|
|
|
57
96
|
set cache(cache: FlatCache);
|
|
58
97
|
/**
|
|
59
98
|
* Use the hash to check if the file has changed
|
|
60
|
-
* @returns {boolean} if the hash is used to check if the file has changed
|
|
99
|
+
* @returns {boolean} if the hash is used to check if the file has changed (default: false)
|
|
61
100
|
*/
|
|
62
101
|
get useCheckSum(): boolean;
|
|
63
102
|
/**
|
|
@@ -67,7 +106,7 @@ declare class FileEntryCache {
|
|
|
67
106
|
set useCheckSum(value: boolean);
|
|
68
107
|
/**
|
|
69
108
|
* Use the modified time to check if the file has changed
|
|
70
|
-
* @returns {boolean} if the modified time is used to check if the file has changed
|
|
109
|
+
* @returns {boolean} if the modified time is used to check if the file has changed (default: true)
|
|
71
110
|
*/
|
|
72
111
|
get useModifiedTime(): boolean;
|
|
73
112
|
/**
|
|
@@ -77,7 +116,7 @@ declare class FileEntryCache {
|
|
|
77
116
|
set useModifiedTime(value: boolean);
|
|
78
117
|
/**
|
|
79
118
|
* Get the hash algorithm
|
|
80
|
-
* @returns {string} The hash algorithm
|
|
119
|
+
* @returns {string} The hash algorithm (default: 'md5')
|
|
81
120
|
*/
|
|
82
121
|
get hashAlgorithm(): string;
|
|
83
122
|
/**
|
|
@@ -85,6 +124,26 @@ declare class FileEntryCache {
|
|
|
85
124
|
* @param {string} value - The value to set
|
|
86
125
|
*/
|
|
87
126
|
set hashAlgorithm(value: string);
|
|
127
|
+
/**
|
|
128
|
+
* Get the current working directory
|
|
129
|
+
* @returns {string} The current working directory (default: process.cwd())
|
|
130
|
+
*/
|
|
131
|
+
get cwd(): string;
|
|
132
|
+
/**
|
|
133
|
+
* Set the current working directory
|
|
134
|
+
* @param {string} value - The value to set
|
|
135
|
+
*/
|
|
136
|
+
set cwd(value: string);
|
|
137
|
+
/**
|
|
138
|
+
* Get whether to restrict paths to cwd boundaries
|
|
139
|
+
* @returns {boolean} Whether strict path checking is enabled (default: true)
|
|
140
|
+
*/
|
|
141
|
+
get strictPaths(): boolean;
|
|
142
|
+
/**
|
|
143
|
+
* Set whether to restrict paths to cwd boundaries
|
|
144
|
+
* @param {boolean} value - The value to set
|
|
145
|
+
*/
|
|
146
|
+
set strictPaths(value: boolean);
|
|
88
147
|
/**
|
|
89
148
|
* Given a buffer, calculate md5 hash of its content.
|
|
90
149
|
* @method getHash
|
|
@@ -173,11 +232,23 @@ declare class FileEntryCache {
|
|
|
173
232
|
getFileDescriptorsByPath(filePath: string): FileDescriptor[];
|
|
174
233
|
/**
|
|
175
234
|
* Get the Absolute Path. If it is already absolute it will return the path as is.
|
|
235
|
+
* When strictPaths is enabled, ensures the resolved path stays within cwd boundaries.
|
|
176
236
|
* @method getAbsolutePath
|
|
177
237
|
* @param filePath - The file path to get the absolute path for
|
|
178
238
|
* @returns {string}
|
|
239
|
+
* @throws {Error} When strictPaths is true and path would resolve outside cwd
|
|
179
240
|
*/
|
|
180
241
|
getAbsolutePath(filePath: string): string;
|
|
242
|
+
/**
|
|
243
|
+
* Get the Absolute Path with a custom working directory. If it is already absolute it will return the path as is.
|
|
244
|
+
* When strictPaths is enabled, ensures the resolved path stays within the provided cwd boundaries.
|
|
245
|
+
* @method getAbsolutePathWithCwd
|
|
246
|
+
* @param filePath - The file path to get the absolute path for
|
|
247
|
+
* @param cwd - The custom working directory to resolve relative paths from
|
|
248
|
+
* @returns {string}
|
|
249
|
+
* @throws {Error} When strictPaths is true and path would resolve outside the provided cwd
|
|
250
|
+
*/
|
|
251
|
+
getAbsolutePathWithCwd(filePath: string, cwd: string): string;
|
|
181
252
|
/**
|
|
182
253
|
* Rename cache keys that start with a given path prefix.
|
|
183
254
|
* @method renameCacheKeys
|
package/dist/index.js
CHANGED
|
@@ -6,14 +6,15 @@ import {
|
|
|
6
6
|
createFromFile as createFlatCacheFile,
|
|
7
7
|
FlatCache
|
|
8
8
|
} from "flat-cache";
|
|
9
|
-
function createFromFile(filePath, useCheckSum) {
|
|
9
|
+
function createFromFile(filePath, useCheckSum, cwd) {
|
|
10
10
|
const fname = path.basename(filePath);
|
|
11
11
|
const directory = path.dirname(filePath);
|
|
12
|
-
return create(fname, directory, useCheckSum);
|
|
12
|
+
return create(fname, directory, useCheckSum, cwd);
|
|
13
13
|
}
|
|
14
|
-
function create(cacheId, cacheDirectory, useCheckSum) {
|
|
14
|
+
function create(cacheId, cacheDirectory, useCheckSum, cwd) {
|
|
15
15
|
const options = {
|
|
16
16
|
useCheckSum,
|
|
17
|
+
cwd,
|
|
17
18
|
cache: {
|
|
18
19
|
cacheId,
|
|
19
20
|
cacheDir: cacheDirectory
|
|
@@ -37,9 +38,11 @@ var FileEntryCache = class {
|
|
|
37
38
|
_useCheckSum = false;
|
|
38
39
|
_useModifiedTime = true;
|
|
39
40
|
_hashAlgorithm = "md5";
|
|
41
|
+
_cwd = process.cwd();
|
|
42
|
+
_strictPaths = true;
|
|
40
43
|
/**
|
|
41
44
|
* Create a new FileEntryCache instance
|
|
42
|
-
* @param options - The options for the FileEntryCache
|
|
45
|
+
* @param options - The options for the FileEntryCache (all properties are optional with defaults)
|
|
43
46
|
*/
|
|
44
47
|
constructor(options) {
|
|
45
48
|
if (options?.cache) {
|
|
@@ -54,6 +57,12 @@ var FileEntryCache = class {
|
|
|
54
57
|
if (options?.hashAlgorithm) {
|
|
55
58
|
this._hashAlgorithm = options.hashAlgorithm;
|
|
56
59
|
}
|
|
60
|
+
if (options?.cwd) {
|
|
61
|
+
this._cwd = options.cwd;
|
|
62
|
+
}
|
|
63
|
+
if (options?.strictPaths !== void 0) {
|
|
64
|
+
this._strictPaths = options.strictPaths;
|
|
65
|
+
}
|
|
57
66
|
}
|
|
58
67
|
/**
|
|
59
68
|
* Get the cache
|
|
@@ -71,7 +80,7 @@ var FileEntryCache = class {
|
|
|
71
80
|
}
|
|
72
81
|
/**
|
|
73
82
|
* Use the hash to check if the file has changed
|
|
74
|
-
* @returns {boolean} if the hash is used to check if the file has changed
|
|
83
|
+
* @returns {boolean} if the hash is used to check if the file has changed (default: false)
|
|
75
84
|
*/
|
|
76
85
|
get useCheckSum() {
|
|
77
86
|
return this._useCheckSum;
|
|
@@ -85,7 +94,7 @@ var FileEntryCache = class {
|
|
|
85
94
|
}
|
|
86
95
|
/**
|
|
87
96
|
* Use the modified time to check if the file has changed
|
|
88
|
-
* @returns {boolean} if the modified time is used to check if the file has changed
|
|
97
|
+
* @returns {boolean} if the modified time is used to check if the file has changed (default: true)
|
|
89
98
|
*/
|
|
90
99
|
get useModifiedTime() {
|
|
91
100
|
return this._useModifiedTime;
|
|
@@ -99,7 +108,7 @@ var FileEntryCache = class {
|
|
|
99
108
|
}
|
|
100
109
|
/**
|
|
101
110
|
* Get the hash algorithm
|
|
102
|
-
* @returns {string} The hash algorithm
|
|
111
|
+
* @returns {string} The hash algorithm (default: 'md5')
|
|
103
112
|
*/
|
|
104
113
|
get hashAlgorithm() {
|
|
105
114
|
return this._hashAlgorithm;
|
|
@@ -111,6 +120,34 @@ var FileEntryCache = class {
|
|
|
111
120
|
set hashAlgorithm(value) {
|
|
112
121
|
this._hashAlgorithm = value;
|
|
113
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Get the current working directory
|
|
125
|
+
* @returns {string} The current working directory (default: process.cwd())
|
|
126
|
+
*/
|
|
127
|
+
get cwd() {
|
|
128
|
+
return this._cwd;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Set the current working directory
|
|
132
|
+
* @param {string} value - The value to set
|
|
133
|
+
*/
|
|
134
|
+
set cwd(value) {
|
|
135
|
+
this._cwd = value;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get whether to restrict paths to cwd boundaries
|
|
139
|
+
* @returns {boolean} Whether strict path checking is enabled (default: true)
|
|
140
|
+
*/
|
|
141
|
+
get strictPaths() {
|
|
142
|
+
return this._strictPaths;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Set whether to restrict paths to cwd boundaries
|
|
146
|
+
* @param {boolean} value - The value to set
|
|
147
|
+
*/
|
|
148
|
+
set strictPaths(value) {
|
|
149
|
+
this._strictPaths = value;
|
|
150
|
+
}
|
|
114
151
|
/**
|
|
115
152
|
* Given a buffer, calculate md5 hash of its content.
|
|
116
153
|
* @method getHash
|
|
@@ -335,13 +372,54 @@ var FileEntryCache = class {
|
|
|
335
372
|
}
|
|
336
373
|
/**
|
|
337
374
|
* Get the Absolute Path. If it is already absolute it will return the path as is.
|
|
375
|
+
* When strictPaths is enabled, ensures the resolved path stays within cwd boundaries.
|
|
338
376
|
* @method getAbsolutePath
|
|
339
377
|
* @param filePath - The file path to get the absolute path for
|
|
340
378
|
* @returns {string}
|
|
379
|
+
* @throws {Error} When strictPaths is true and path would resolve outside cwd
|
|
341
380
|
*/
|
|
342
381
|
getAbsolutePath(filePath) {
|
|
343
382
|
if (this.isRelativePath(filePath)) {
|
|
344
|
-
|
|
383
|
+
const sanitizedPath = filePath.replace(/\0/g, "");
|
|
384
|
+
const resolved = path.resolve(this._cwd, sanitizedPath);
|
|
385
|
+
if (this._strictPaths) {
|
|
386
|
+
const normalizedResolved = path.normalize(resolved);
|
|
387
|
+
const normalizedCwd = path.normalize(this._cwd);
|
|
388
|
+
const isWithinCwd = normalizedResolved === normalizedCwd || normalizedResolved.startsWith(normalizedCwd + path.sep);
|
|
389
|
+
if (!isWithinCwd) {
|
|
390
|
+
throw new Error(
|
|
391
|
+
`Path traversal attempt blocked: "${filePath}" resolves outside of working directory "${this._cwd}"`
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return resolved;
|
|
396
|
+
}
|
|
397
|
+
return filePath;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Get the Absolute Path with a custom working directory. If it is already absolute it will return the path as is.
|
|
401
|
+
* When strictPaths is enabled, ensures the resolved path stays within the provided cwd boundaries.
|
|
402
|
+
* @method getAbsolutePathWithCwd
|
|
403
|
+
* @param filePath - The file path to get the absolute path for
|
|
404
|
+
* @param cwd - The custom working directory to resolve relative paths from
|
|
405
|
+
* @returns {string}
|
|
406
|
+
* @throws {Error} When strictPaths is true and path would resolve outside the provided cwd
|
|
407
|
+
*/
|
|
408
|
+
getAbsolutePathWithCwd(filePath, cwd) {
|
|
409
|
+
if (this.isRelativePath(filePath)) {
|
|
410
|
+
const sanitizedPath = filePath.replace(/\0/g, "");
|
|
411
|
+
const resolved = path.resolve(cwd, sanitizedPath);
|
|
412
|
+
if (this._strictPaths) {
|
|
413
|
+
const normalizedResolved = path.normalize(resolved);
|
|
414
|
+
const normalizedCwd = path.normalize(cwd);
|
|
415
|
+
const isWithinCwd = normalizedResolved === normalizedCwd || normalizedResolved.startsWith(normalizedCwd + path.sep);
|
|
416
|
+
if (!isWithinCwd) {
|
|
417
|
+
throw new Error(
|
|
418
|
+
`Path traversal attempt blocked: "${filePath}" resolves outside of working directory "${cwd}"`
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return resolved;
|
|
345
423
|
}
|
|
346
424
|
return filePath;
|
|
347
425
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "file-entry-cache",
|
|
3
|
-
"version": "11.0.0-beta.
|
|
3
|
+
"version": "11.0.0-beta.2",
|
|
4
4
|
"description": "A lightweight cache for file metadata, ideal for processes that work on a specific set of files and only need to reprocess files that have changed since the last run",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"vitest": "^3.2.4"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"flat-cache": "^6.1.
|
|
41
|
+
"flat-cache": "^6.1.17"
|
|
42
42
|
},
|
|
43
43
|
"files": [
|
|
44
44
|
"dist",
|