20 lines
1.0 KiB
TypeScript
20 lines
1.0 KiB
TypeScript
import { realpath } from "node:fs/promises";
|
|
import path from "node:path";
|
|
|
|
/** Registration may name the workbench through its guest alias. Only that
|
|
* outer alias is permitted: resources and each checkout remain physical,
|
|
* directly contained directories. Persist the resulting root-relative path.
|
|
*/
|
|
export async function managedResourcePath(workbench: string, directory: string): Promise<string> {
|
|
const root = await realpath(workbench);
|
|
const selected = path.resolve(root, directory);
|
|
const name = path.basename(selected);
|
|
const resources = path.dirname(selected);
|
|
if (path.basename(resources) !== "resources" || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name))
|
|
throw new Error(`Repository is outside the managed workbench: ${directory}`);
|
|
const relative = `resources/${name}`;
|
|
if ((await realpath(path.dirname(resources))) !== root || (await realpath(selected)) !== path.join(root, relative))
|
|
throw new Error(`Managed repository path crosses a symlink or escapes the workbench: ${directory}`);
|
|
return relative;
|
|
}
|