Skip to content

Commit c7c268c

Browse files
Copilotstreamich
andcommitted
fix: resolve security regex issue and constructor bug in FSA classes
Co-authored-by: streamich <[email protected]>
1 parent a26e1cc commit c7c268c

13 files changed

+114
-97
lines changed

src/fsa/CoreFileSystemDirectoryHandle.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
newTypeMismatchError,
1010
} from './util';
1111
import { CoreFileSystemFileHandle } from './CoreFileSystemFileHandle';
12-
import type {
12+
import type {
1313
CoreFsaContext,
1414
GetDirectoryHandleOptions,
1515
GetFileHandleOptions,
@@ -247,6 +247,9 @@ export class CoreFileSystemDirectoryHandle extends CoreFileSystemHandle implemen
247247
possibleDescendant instanceof CoreFileSystemDirectoryHandle ||
248248
possibleDescendant instanceof CoreFileSystemFileHandle
249249
) {
250+
// First check if they are from the same core instance
251+
if ((possibleDescendant as any)._core !== this._core) return null;
252+
250253
const path = this.__path;
251254
const childPath = possibleDescendant.__path;
252255
if (!childPath.startsWith(path)) return null;
@@ -271,4 +274,4 @@ export class CoreFileSystemDirectoryHandle extends CoreFileSystemHandle implemen
271274
}
272275
throw error;
273276
}
274-
}
277+
}

src/fsa/CoreFileSystemFileHandle.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import { CoreFileSystemHandle } from './CoreFileSystemHandle';
22
import { CoreFileSystemSyncAccessHandle } from './CoreFileSystemSyncAccessHandle';
33
import { assertCanWrite, basename, ctx as createCtx, newNotAllowedError } from './util';
44
import { CoreFileSystemWritableFileStream } from './CoreFileSystemWritableFileStream';
5-
import type {
6-
CoreFsaContext,
5+
import type {
6+
CoreFsaContext,
77
CreateWritableOptions,
8-
IFileSystemFileHandle,
9-
IFileSystemSyncAccessHandle
8+
IFileSystemFileHandle,
9+
IFileSystemSyncAccessHandle,
1010
} from './types';
1111
import type { Superblock } from '../core/Superblock';
1212
import { Buffer } from '../internal/buffer';
@@ -36,18 +36,18 @@ export class CoreFileSystemFileHandle extends CoreFileSystemHandle implements IF
3636
const path = this.__path;
3737
const link = this._core.getResolvedLinkOrThrow(path);
3838
const node = link.getNode();
39-
39+
4040
if (!node.isFile()) {
4141
throw new Error('Not a file');
4242
}
4343

4444
// Get file stats for lastModified
4545
const lastModified = node.mtime ? node.mtime.getTime() : Date.now();
46-
46+
4747
// Read file content
4848
const buffer = node.getBuffer();
4949
const data = new Uint8Array(buffer);
50-
50+
5151
const file = new File([data], this.name, { lastModified });
5252
return file;
5353
} catch (error) {
@@ -79,4 +79,4 @@ export class CoreFileSystemFileHandle extends CoreFileSystemHandle implements IF
7979
assertCanWrite(this.ctx.mode);
8080
return new CoreFileSystemWritableFileStream(this._core, this.__path, keepExistingData);
8181
}
82-
}
82+
}

src/fsa/CoreFileSystemHandle.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,4 @@ export abstract class CoreFileSystemHandle implements IFileSystemHandle {
4848
): CorePermissionStatus {
4949
throw new Error('Not implemented');
5050
}
51-
}
51+
}

src/fsa/CoreFileSystemSyncAccessHandle.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,7 @@ export class CoreFileSystemSyncAccessHandle implements IFileSystemSyncAccessHand
6969
/**
7070
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemSyncAccessHandle/read
7171
*/
72-
public async read(
73-
buffer: ArrayBuffer | ArrayBufferView,
74-
options: FileSystemReadWriteOptions = {},
75-
): Promise<number> {
72+
public async read(buffer: ArrayBuffer | ArrayBufferView, options: FileSystemReadWriteOptions = {}): Promise<number> {
7673
const fd = this._ensureOpen();
7774
const { at: position = 0 } = options;
7875

@@ -131,4 +128,4 @@ export class CoreFileSystemSyncAccessHandle implements IFileSystemSyncAccessHand
131128
throw error;
132129
}
133130
}
134-
}
131+
}

src/fsa/CoreFileSystemWritableFileStream.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,15 @@ export class CoreFileSystemWritableFileStream extends WritableStream implements
1515
private readonly _core: Superblock;
1616
private readonly _path: string;
1717

18-
constructor(
19-
core: Superblock,
20-
path: string,
21-
keepExistingData: boolean = false,
22-
) {
18+
constructor(core: Superblock, path: string, keepExistingData: boolean = false) {
19+
let fd: number | undefined;
20+
2321
super({
24-
start: (controller) => {
22+
start: controller => {
2523
// Open file for writing
2624
const flags = keepExistingData ? FLAGS['r+'] : FLAGS.w;
2725
try {
28-
this._fd = core.open(path, flags, MODE.FILE);
26+
fd = core.open(path, flags, MODE.FILE);
2927
} catch (error) {
3028
if (error && typeof error === 'object' && error.code === ERROR_CODE.EACCES) {
3129
throw newNotAllowedError();
@@ -49,8 +47,10 @@ export class CoreFileSystemWritableFileStream extends WritableStream implements
4947
}
5048
},
5149
});
50+
5251
this._core = core;
5352
this._path = path;
53+
this._fd = fd;
5454
}
5555

5656
/**
@@ -166,4 +166,4 @@ export class CoreFileSystemWritableFileStream extends WritableStream implements
166166
}
167167
throw new Error('Unsupported data type');
168168
}
169-
}
169+
}

src/fsa/CorePermissionStatus.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ export class CorePermissionStatus implements IPermissionStatus {
1111
this.name = name;
1212
this.state = state;
1313
}
14-
}
14+
}

src/fsa/__tests__/CoreFileSystemDirectoryHandle.test.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ onlyOnNode20('CoreFileSystemDirectoryHandle', () => {
120120

121121
test('throws error when directory does not exist and create is false', async () => {
122122
const { dir } = setup();
123-
await expect(dir.getDirectoryHandle('nonexistent')).rejects.toThrow('A requested file or directory could not be found');
123+
await expect(dir.getDirectoryHandle('nonexistent')).rejects.toThrow(
124+
'A requested file or directory could not be found',
125+
);
124126
});
125127
});
126128

@@ -141,7 +143,9 @@ onlyOnNode20('CoreFileSystemDirectoryHandle', () => {
141143

142144
test('throws error when file does not exist and create is false', async () => {
143145
const { dir } = setup();
144-
await expect(dir.getFileHandle('nonexistent.txt')).rejects.toThrow('A requested file or directory could not be found');
146+
await expect(dir.getFileHandle('nonexistent.txt')).rejects.toThrow(
147+
'A requested file or directory could not be found',
148+
);
145149
});
146150
});
147151

@@ -155,13 +159,17 @@ onlyOnNode20('CoreFileSystemDirectoryHandle', () => {
155159
test('can remove an empty directory', async () => {
156160
const { dir } = setup({ folder: null });
157161
await dir.removeEntry('folder');
158-
await expect(dir.getDirectoryHandle('folder')).rejects.toThrow('A requested file or directory could not be found');
162+
await expect(dir.getDirectoryHandle('folder')).rejects.toThrow(
163+
'A requested file or directory could not be found',
164+
);
159165
});
160166

161167
test('can remove directory recursively', async () => {
162168
const { dir } = setup({ 'folder/file.txt': 'content' });
163169
await dir.removeEntry('folder', { recursive: true });
164-
await expect(dir.getDirectoryHandle('folder')).rejects.toThrow('A requested file or directory could not be found');
170+
await expect(dir.getDirectoryHandle('folder')).rejects.toThrow(
171+
'A requested file or directory could not be found',
172+
);
165173
});
166174
});
167175

@@ -183,19 +191,19 @@ onlyOnNode20('CoreFileSystemDirectoryHandle', () => {
183191

184192
test('returns null for non-descendant', async () => {
185193
const { dir: dir1 } = setup({ 'file1.txt': 'content' });
186-
194+
187195
// Create completely different core and root path
188196
const core2 = Superblock.fromJSON({ 'different/file2.txt': 'content' }, '/');
189197
// Use a different path that does not start with dir1's path
190198
const dir2 = new CoreFileSystemDirectoryHandle(core2, '/some-completely-different-path/', { mode: 'readwrite' });
191-
199+
192200
// This will try to get file2.txt from /some-completely-different-path/ which doesn't exist
193201
// So we need to actually create the file in the expected location
194202
const actualDir2 = new CoreFileSystemDirectoryHandle(core2, '/different/', { mode: 'readwrite' });
195203
const file2 = await actualDir2.getFileHandle('file2.txt');
196-
204+
197205
const resolved = await dir1.resolve(file2);
198206
expect(resolved).toBeNull();
199207
});
200208
});
201-
});
209+
});

src/fsa/__tests__/CoreFileSystemFileHandle.test.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ onlyOnNode20('CoreFileSystemFileHandle', () => {
3636
const { core } = setup();
3737
// Create file with binary content
3838
core.writeFile('/binary.dat', content, 0x200 | 0x40 | 0x1, 0o644); // O_CREAT | O_TRUNC | O_WRONLY
39-
39+
4040
const dir = new CoreFileSystemDirectoryHandle(core, '/', { mode: 'readwrite' });
4141
const fileHandle = await dir.getFileHandle('binary.dat');
4242
const file = await fileHandle.getFile();
43-
43+
4444
expect(file.size).toBe(5);
4545
const arrayBuffer = await file.arrayBuffer();
4646
const uint8Array = new Uint8Array(arrayBuffer);
@@ -54,10 +54,10 @@ onlyOnNode20('CoreFileSystemFileHandle', () => {
5454
const fileHandle = await dir.getFileHandle('test.txt');
5555
const writable = await fileHandle.createWritable();
5656
expect(writable).toBeDefined();
57-
57+
5858
await writable.write('new content');
5959
await writable.close();
60-
60+
6161
const file = await fileHandle.getFile();
6262
expect(await file.text()).toBe('new content');
6363
});
@@ -67,11 +67,11 @@ onlyOnNode20('CoreFileSystemFileHandle', () => {
6767
const fileHandle = await dir.getFileHandle('test.txt');
6868
const writable = await fileHandle.createWritable({ keepExistingData: true });
6969
expect(writable).toBeDefined();
70-
70+
7171
await writable.seek(8); // Move past "initial "
7272
await writable.write('new data');
7373
await writable.close();
74-
74+
7575
const file = await fileHandle.getFile();
7676
expect(await file.text()).toBe('initial new data');
7777
});
@@ -86,9 +86,9 @@ onlyOnNode20('CoreFileSystemFileHandle', () => {
8686

8787
test('returns function when sync handle allowed', async () => {
8888
const core = Superblock.fromJSON({ 'test.txt': 'content' }, '/');
89-
const dir = new CoreFileSystemDirectoryHandle(core, '/', {
90-
mode: 'readwrite',
91-
syncHandleAllowed: true
89+
const dir = new CoreFileSystemDirectoryHandle(core, '/', {
90+
mode: 'readwrite',
91+
syncHandleAllowed: true,
9292
});
9393
const fileHandle = await dir.getFileHandle('test.txt');
9494
expect(fileHandle.createSyncAccessHandle).toBeDefined();
@@ -113,4 +113,4 @@ onlyOnNode20('CoreFileSystemFileHandle', () => {
113113
expect(await file.text()).toBe('content');
114114
});
115115
});
116-
});
116+
});

src/fsa/__tests__/CoreFileSystemHandle.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,19 @@ onlyOnNode20('CoreFileSystemHandle', () => {
3333
});
3434

3535
test('isSameEntry returns false for different handles', async () => {
36-
const { dir } = setup({
36+
const { dir } = setup({
3737
'test1.txt': 'content1',
38-
'test2.txt': 'content2'
38+
'test2.txt': 'content2',
3939
});
4040
const file1 = await dir.getFileHandle('test1.txt');
4141
const file2 = await dir.getFileHandle('test2.txt');
4242
expect(file1.isSameEntry(file2)).toBe(false);
4343
});
4444

4545
test('isSameEntry returns false for different types', async () => {
46-
const { dir } = setup({
46+
const { dir } = setup({
4747
'test.txt': 'content',
48-
folder: null
48+
folder: null,
4949
});
5050
const file = await dir.getFileHandle('test.txt');
5151
const folder = await dir.getDirectoryHandle('folder');
@@ -69,4 +69,4 @@ onlyOnNode20('CoreFileSystemHandle', () => {
6969
const file = await dir.getFileHandle('test.txt');
7070
await expect(file.remove()).rejects.toThrow('Not implemented');
7171
});
72-
});
72+
});

0 commit comments

Comments
 (0)