Files

19 lines
1.3 KiB
JavaScript

import { readFile, realpath, stat } from "node:fs/promises";
import { resolve, relative, isAbsolute, extname } from "node:path";
// Keep UI entrypoints and assets within the same bound as the installed host's
// MAX_PLUGIN_UI_ASSET_BYTES (crates/dbx-plugin-runtime/src/plugins/assets.rs).
const MAX_PLUGIN_UI_ASSET_BYTES = 32 * 1024 * 1024;
export async function readAsset(root, path) {
if (typeof path !== "string" || !path || path.includes("\0") || isAbsolute(path)) throw new Error("Invalid asset path");
const base = await realpath(root),
file = await realpath(resolve(base, path));
const rel = relative(base, file);
if (rel.startsWith("..") || isAbsolute(rel)) throw new Error("Asset is outside UI root");
const info = await stat(file);
if (!info.isFile()) throw new Error("Asset is not a file");
if (info.size > MAX_PLUGIN_UI_ASSET_BYTES) throw new Error(`Asset exceeds ${MAX_PLUGIN_UI_ASSET_BYTES} byte limit`);
const types = { ".html": "text/html", ".js": "text/javascript", ".css": "text/css", ".json": "application/json", ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", ".svg": "image/svg+xml", ".woff2": "font/woff2" };
return { dataBase64: (await readFile(file)).toString("base64"), contentType: types[extname(file)] || "application/octet-stream" };
}