diff --git a/src/permission/fs_permission.cc b/src/permission/fs_permission.cc index 0baf1291a96..b1a7de5ef83 100644 --- a/src/permission/fs_permission.cc +++ b/src/permission/fs_permission.cc @@ -176,21 +176,21 @@ void FSPermission::Drop(Environment* env, } void FSPermission::RevokeAccess(PermissionScope perm, const std::string& res) { - const std::string path = WildcardIfDir(res); - if (perm == PermissionScope::kFileSystemRead) { - auto it = - std::find(granted_paths_in_.begin(), granted_paths_in_.end(), path); - if (it != granted_paths_in_.end()) { - granted_paths_in_.erase(it); - RebuildTree(PermissionScope::kFileSystemRead); - } - } else if (perm == PermissionScope::kFileSystemWrite) { - auto it = - std::find(granted_paths_out_.begin(), granted_paths_out_.end(), path); - if (it != granted_paths_out_.end()) { - granted_paths_out_.erase(it); - RebuildTree(PermissionScope::kFileSystemWrite); - } + if (perm != PermissionScope::kFileSystemRead && + perm != PermissionScope::kFileSystemWrite) { + return; + } + std::string wildcard = res; + if (wildcard.back() != node::kPathSeparator) { + wildcard += node::kPathSeparator; + } + wildcard += '*'; + auto& paths = perm == PermissionScope::kFileSystemRead ? granted_paths_in_ + : granted_paths_out_; + if (std::erase_if(paths, [&](const std::string& p) { + return p == res || p == wildcard; + }) > 0) { + RebuildTree(perm); } } diff --git a/test/parallel/test-permission-drop-fs-granted-path.js b/test/parallel/test-permission-drop-fs-granted-path.js index fdb9b194979..82d04b49040 100644 --- a/test/parallel/test-permission-drop-fs-granted-path.js +++ b/test/parallel/test-permission-drop-fs-granted-path.js @@ -167,6 +167,71 @@ for (const files of [ assert.strictEqual(child.status, 0); } +// Grant a path that does not exist yet, then create it as a directory +// dropping it still revokes the grant +{ + const later = path.join(tmpdir.path, 'later-dir'); + const child = spawnSync(process.execPath, [ + '--permission', + `--allow-fs-read=${later}`, + `--allow-fs-write=${later}`, + '-e', + ` + const assert = require('assert'); + const fs = require('fs'); + const later = ${JSON.stringify(later)}; + + fs.mkdirSync(later); + for (const scope of ['fs.read', 'fs.write']) { + assert.ok(process.permission.has(scope, later)); + + process.permission.drop(scope, later); + + assert.ok(!process.permission.has(scope, later)); + assert.ok(!process.permission.has(scope, later + '/file.txt')); + } + `, + ]); + if (child.status !== 0) { + console.error('Case 6 stderr:', child.stderr?.toString()); + } + assert.strictEqual(child.status, 0); +} + +// Grant a directory, then remove it - dropping it still revokes the grant +{ + const gone = path.join(tmpdir.path, 'gone-dir'); + fs.mkdirSync(gone); + const child = spawnSync(process.execPath, [ + '--permission', + `--allow-fs-read=${gone}`, + `--allow-fs-read=${dir}`, + `--allow-fs-write=${gone}`, + `--allow-fs-write=${dir}`, + '-e', + ` + const assert = require('assert'); + const fs = require('fs'); + const gone = ${JSON.stringify(gone)}; + const dir = ${JSON.stringify(dir)}; + + fs.rmdirSync(gone); + for (const scope of ['fs.read', 'fs.write']) { + assert.ok(process.permission.has(scope, gone)); + + process.permission.drop(scope, gone); + + assert.ok(!process.permission.has(scope, gone)); + assert.ok(process.permission.has(scope, dir + '/item1.txt')); + } + `, + ]); + if (child.status !== 0) { + console.error('Case 7 stderr:', child.stderr?.toString()); + } + assert.strictEqual(child.status, 0); +} + // Drop entire scope without reference - revokes everything { const child = spawnSync(process.execPath, [