|
7 | 7 | readArchiveHeaderSync, |
8 | 8 | readFilesystemSync, |
9 | 9 | readFileSync, |
| 10 | + readFileWithFd, |
10 | 11 | uncacheFilesystem, |
11 | 12 | } from '../src/disk.js'; |
12 | 13 | import { useTmpDir } from './util/tmpDir.js'; |
@@ -72,7 +73,7 @@ function makeFileInfo(offset: string, size: number): FilesystemFileEntry { |
72 | 73 | } |
73 | 74 |
|
74 | 75 | describe('disk', () => { |
75 | | - const { testRunDir, createFixture } = useTmpDir(uncacheAll); |
| 76 | + const { testRunDir, tmpDir, createFixture } = useTmpDir(uncacheAll); |
76 | 77 |
|
77 | 78 | describe('caching', () => { |
78 | 79 | it('uncacheFilesystem should return true for cached and false for uncached', async () => { |
@@ -266,4 +267,56 @@ describe('disk', () => { |
266 | 267 | expect(result.toString('utf8')).toBe(content); |
267 | 268 | }); |
268 | 269 | }); |
| 270 | + |
| 271 | + describe('unpacked file reads', () => { |
| 272 | + function makeUnpackedInfo(size: number): FilesystemFileEntry { |
| 273 | + return { |
| 274 | + offset: '0', |
| 275 | + size, |
| 276 | + unpacked: true, |
| 277 | + executable: false, |
| 278 | + integrity: { hash: '', algorithm: 'SHA256', blocks: [], blockSize: 0 }, |
| 279 | + }; |
| 280 | + } |
| 281 | + |
| 282 | + /** |
| 283 | + * Sets up an archive whose `.unpacked` directory contains a benign file, |
| 284 | + * plus an `outside.txt` file that lives next to the archive (outside the |
| 285 | + * `.unpacked` directory). Returns the filesystem and the on-disk paths. |
| 286 | + */ |
| 287 | + function setupUnpacked(name: string) { |
| 288 | + const baseDir = tmpDir(name); |
| 289 | + const archivePath = path.join(baseDir, `${name}.asar`); |
| 290 | + const unpackedDir = `${archivePath}.unpacked`; |
| 291 | + fs.mkdirpSync(unpackedDir); |
| 292 | + fs.writeFileSync(path.join(unpackedDir, 'inside.txt'), 'inside'); |
| 293 | + fs.writeFileSync(path.join(baseDir, 'outside.txt'), 'outside'); |
| 294 | + const filesystem = makeFilesystem(archivePath, 16); |
| 295 | + return { filesystem, archivePath }; |
| 296 | + } |
| 297 | + |
| 298 | + it('readFileSync reads unpacked files within the unpacked directory', () => { |
| 299 | + const { filesystem } = setupUnpacked('unpacked-read-sync'); |
| 300 | + const info = makeUnpackedInfo('inside'.length); |
| 301 | + expect(readFileSync(filesystem, 'inside.txt', info).toString('utf8')).toBe('inside'); |
| 302 | + }); |
| 303 | + |
| 304 | + it('readFileSync throws when filename escapes the unpacked directory', () => { |
| 305 | + const { filesystem } = setupUnpacked('unpacked-escape-sync'); |
| 306 | + const info = makeUnpackedInfo('outside'.length); |
| 307 | + expect(() => readFileSync(filesystem, '../outside.txt', info)).toThrow('outside'); |
| 308 | + }); |
| 309 | + |
| 310 | + it('readFileWithFd reads unpacked files within the unpacked directory', () => { |
| 311 | + const { filesystem } = setupUnpacked('unpacked-read-fd'); |
| 312 | + const info = makeUnpackedInfo('inside'.length); |
| 313 | + expect(readFileWithFd(-1, filesystem, 'inside.txt', info).toString('utf8')).toBe('inside'); |
| 314 | + }); |
| 315 | + |
| 316 | + it('readFileWithFd throws when filename escapes the unpacked directory', () => { |
| 317 | + const { filesystem } = setupUnpacked('unpacked-escape-fd'); |
| 318 | + const info = makeUnpackedInfo('outside'.length); |
| 319 | + expect(() => readFileWithFd(-1, filesystem, '../outside.txt', info)).toThrow('outside'); |
| 320 | + }); |
| 321 | + }); |
269 | 322 | }); |
0 commit comments