Skip to content

Commit 3328087

Browse files
authored
Merge pull request #1052 from ethereum/enforce-checks
Restrict file operations to workspace / shared folder.
2 parents 306192e + 6b72a8f commit 3328087

File tree

4 files changed

+60
-23
lines changed

4 files changed

+60
-23
lines changed

apps/remix-ide/src/app/files/workspaceFileProvider.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict'
22

33
const FileProvider = require('./fileProvider')
4+
const pathModule = require('path')
45

56
class WorkspaceFileProvider extends FileProvider {
67
constructor () {
@@ -32,8 +33,19 @@ class WorkspaceFileProvider extends FileProvider {
3233
if (path.startsWith(this.workspacesPath + '/' + this.workspace)) return path
3334
if (path.startsWith(this.workspace)) return this.workspacesPath + '/' + this.workspace
3435
path = super.removePrefix(path)
35-
const ret = this.workspacesPath + '/' + this.workspace + '/' + (path === '/' ? '' : path)
36-
return ret.replace(/^\/|\/$/g, '')
36+
let ret = this.workspacesPath + '/' + this.workspace + '/' + (path === '/' ? '' : path)
37+
38+
ret = ret.replace(/^\/|\/$/g, '')
39+
if (!this.isSubDirectory(this.workspacesPath + '/' + this.workspace, ret)) throw new Error('Cannot read/write to path outside workspace')
40+
return ret
41+
}
42+
43+
isSubDirectory (parent, child) {
44+
if (!parent) return false
45+
if (parent === child) return true
46+
const relative = pathModule.relative(parent, child)
47+
48+
return !!relative && relative.split(pathModule.sep)[0] !== '..'
3749
}
3850

3951
resolveDirectory (path, callback) {

libs/remix-ui/file-explorer/src/lib/file-explorer.tsx

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -314,25 +314,32 @@ export const FileExplorer = (props: FileExplorerProps) => {
314314
const createNewFile = (newFilePath: string) => {
315315
const fileManager = state.fileManager
316316

317-
helper.createNonClashingName(newFilePath, filesProvider, async (error, newName) => {
318-
if (error) {
319-
modal('Create File Failed', error, {
320-
label: 'Close',
321-
fn: async () => {}
322-
}, null)
323-
} else {
324-
const createFile = await fileManager.writeFile(newName, '')
325-
326-
if (!createFile) {
327-
return toast('Failed to create file ' + newName)
317+
try {
318+
helper.createNonClashingName(newFilePath, filesProvider, async (error, newName) => {
319+
if (error) {
320+
modal('Create File Failed', error, {
321+
label: 'Close',
322+
fn: async () => {}
323+
}, null)
328324
} else {
329-
await fileManager.open(newName)
330-
setState(prevState => {
331-
return { ...prevState, focusElement: [{ key: newName, type: 'file' }] }
332-
})
325+
const createFile = await fileManager.writeFile(newName, '')
326+
327+
if (!createFile) {
328+
return toast('Failed to create file ' + newName)
329+
} else {
330+
await fileManager.open(newName)
331+
setState(prevState => {
332+
return { ...prevState, focusElement: [{ key: newName, type: 'file' }] }
333+
})
334+
}
333335
}
334-
}
335-
})
336+
})
337+
} catch (error) {
338+
return modal('File Creation Failed', error.message, {
339+
label: 'Close',
340+
fn: async () => {}
341+
}, null)
342+
}
336343
}
337344

338345
const createNewFolder = async (newFolderPath: string) => {
@@ -353,8 +360,10 @@ export const FileExplorer = (props: FileExplorerProps) => {
353360
return { ...prevState, focusElement: [{ key: newFolderPath, type: 'folder' }] }
354361
})
355362
} catch (e) {
356-
console.log('error: ', e)
357-
toast('Failed to create folder: ' + newFolderPath)
363+
return modal('Folder Creation Failed', e.message, {
364+
label: 'Close',
365+
fn: async () => {}
366+
}, null)
358367
}
359368
}
360369

libs/remixd/src/utils.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,25 @@ import * as pathModule from 'path'
1212
function absolutePath (path: string, sharedFolder:string): string {
1313
path = normalizePath(path)
1414
path = pathModule.resolve(sharedFolder, path)
15+
if (!isSubDirectory(pathModule.resolve(process.cwd(), sharedFolder), path)) throw new Error('Cannot read/write to path outside shared folder.')
1516
return path
1617
}
1718

19+
/**
20+
* returns a true if child is sub-directory of parent.
21+
*
22+
* @param {String} parent - path to parent directory
23+
* @param {String} child - child path
24+
* @return {Boolean}
25+
*/
26+
function isSubDirectory (parent: string, child: string) {
27+
if (!parent) return false
28+
if (parent === child) return true
29+
const relative = pathModule.relative(parent, child)
30+
31+
return !!relative && relative.split(pathModule.sep)[0] !== '..'
32+
}
33+
1834
/**
1935
* return the relative path of the given @arg path
2036
*

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"nightwatch_local_signingMessage": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/signingMessage.test.js --env=chrome",
6868
"nightwatch_local_specialFunctions": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/specialFunctions.test.js --env=chrome",
6969
"nightwatch_local_solidityUnitTests": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/solidityUnittests.test.js --env=chrome",
70-
"nightwatch_local_remixd": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/remixd.test.js --env=chrome",
70+
"nightwatch_local_remixd": "npm run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/remixd.test.js --env=chrome",
7171
"nightwatch_local_terminal": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/terminal.test.js --env=chrome",
7272
"nightwatch_local_gist": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/gist.test.js --env=chrome",
7373
"nightwatch_local_workspace": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/workspace.test.js --env=chrome",
@@ -85,7 +85,7 @@
8585
"nightwatch_local_url": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/url.test.js --env=chrome",
8686
"nightwatch_local_verticalIconscontextmenu": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/verticalIconsPanel.test.js --env=chrome",
8787
"onchange": "onchange apps/remix-ide/build/app.js -- npm-run-all lint",
88-
"remixd": "nx build remixd & nx serve remixd --folder=./apps/remix-ide/contracts --remixide=http://127.0.0.1:8080",
88+
"remixd": "nx build remixd && nx serve remixd --folder=./apps/remix-ide/contracts --remixide=http://127.0.0.1:8080",
8989
"selenium": "selenium-standalone start",
9090
"selenium-install": "selenium-standalone install",
9191
"sourcemap": "exorcist --root ../ apps/remix-ide/build/app.js.map > apps/remix-ide/build/app.js",

0 commit comments

Comments
 (0)