fix
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
|||||||
arePluginNeedsApproved,
|
arePluginNeedsApproved,
|
||||||
compilePluginTypeScript,
|
compilePluginTypeScript,
|
||||||
computePluginNeedsHash,
|
computePluginNeedsHash,
|
||||||
|
ensurePluginExtracted,
|
||||||
loadPluginBundle,
|
loadPluginBundle,
|
||||||
type PluginState,
|
type PluginState,
|
||||||
} from "./plugin-state-bundle";
|
} from "./plugin-state-bundle";
|
||||||
@@ -70,6 +71,31 @@ describe("loadPluginBundle", () => {
|
|||||||
expect(bundle.size).toBe(4);
|
expect(bundle.size).toBe(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("keeps helper DLLs out of the native platform binary map", async () => {
|
||||||
|
const root = await createTempRoot();
|
||||||
|
const AdmZip = require("adm-zip");
|
||||||
|
const zip = new AdmZip();
|
||||||
|
zip.addFile("config.json", Buffer.from(JSON.stringify({
|
||||||
|
name: "Plink",
|
||||||
|
apiVersion: 2,
|
||||||
|
runtime: "native",
|
||||||
|
uiEntry: "src/ui.ts",
|
||||||
|
})));
|
||||||
|
zip.addFile("plink.html", Buffer.from("<div id=\"plink-root\"></div>"));
|
||||||
|
zip.addFile("plink.css", Buffer.from("#plink-root { display: block; }"));
|
||||||
|
zip.addFile("src/ui.ts", Buffer.from("document.body.dataset.plugin = 'plink';"));
|
||||||
|
zip.addFile("plink-windows-amd64.dll", Buffer.from("entry-dll"));
|
||||||
|
zip.addFile("plink-payload.dll", Buffer.from("helper-dll"));
|
||||||
|
zip.writeZip(join(root, "plink.zip"));
|
||||||
|
|
||||||
|
await ensurePluginExtracted(root, "plink", (name) => name);
|
||||||
|
const manifest = JSON.parse(await readFile(join(root, "plink", "manifest.json"), "utf-8"));
|
||||||
|
expect(manifest.binaries["windows-amd64"]).toBe("plink-windows-amd64.dll");
|
||||||
|
|
||||||
|
const bundle = await loadPluginBundle(root, "plink", async () => {}, "Windows 11", "amd64");
|
||||||
|
expect(bundle.binaryPath).toBe(join(root, "plink", "plink-windows-amd64.dll"));
|
||||||
|
});
|
||||||
|
|
||||||
test("computes stable need hashes and invalidates changed approvals", () => {
|
test("computes stable need hashes and invalidates changed approvals", () => {
|
||||||
const state: PluginState = {
|
const state: PluginState = {
|
||||||
enabled: {},
|
enabled: {},
|
||||||
|
|||||||
@@ -149,11 +149,17 @@ export async function ensurePluginExtracted(
|
|||||||
throw new Error(`Invalid plugin bundle: ${safeId} (missing .html, .css, and either .js or src/ui.ts)`);
|
throw new Error(`Invalid plugin bundle: ${safeId} (missing .html, .css, and either .js or src/ui.ts)`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const binariesMap: Record<string, string> = {};
|
|
||||||
for (const [filename, data] of nativeBinaries) {
|
for (const [filename, data] of nativeBinaries) {
|
||||||
await fs.writeFile(path.join(pluginDir, filename), data);
|
await fs.writeFile(path.join(pluginDir, filename), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const binariesMap: Record<string, string> = {};
|
||||||
|
applyConfiguredNativeBinaries(binariesMap, extraConfig, nativeBinaries);
|
||||||
|
const nativeBinaryNames = Array.from(nativeBinaries.keys())
|
||||||
|
.sort((a, b) => nativeBinaryPriority(a, safeId) - nativeBinaryPriority(b, safeId) || a.localeCompare(b));
|
||||||
|
for (const filename of nativeBinaryNames) {
|
||||||
const platformKey = derivePlatformKey(filename);
|
const platformKey = derivePlatformKey(filename);
|
||||||
if (platformKey) {
|
if (platformKey && !binariesMap[platformKey]) {
|
||||||
binariesMap[platformKey] = filename;
|
binariesMap[platformKey] = filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,6 +209,7 @@ export async function ensurePluginExtracted(
|
|||||||
runtime,
|
runtime,
|
||||||
version: extraConfig.version || "1.0.0",
|
version: extraConfig.version || "1.0.0",
|
||||||
description: extraConfig.description,
|
description: extraConfig.description,
|
||||||
|
...(typeof extraConfig.binary === "string" && extraConfig.binary && { binary: extraConfig.binary }),
|
||||||
...(runtime === "wasm" && { wasm: String(extraConfig.wasm || wasmEntry?.filename || binariesMap["wasm32-wasi"] || "") }),
|
...(runtime === "wasm" && { wasm: String(extraConfig.wasm || wasmEntry?.filename || binariesMap["wasm32-wasi"] || "") }),
|
||||||
...(needs && { needs }),
|
...(needs && { needs }),
|
||||||
binaries: binariesMap,
|
binaries: binariesMap,
|
||||||
@@ -345,7 +352,7 @@ export async function loadPluginBundle(
|
|||||||
const files = await fs.readdir(dir);
|
const files = await fs.readdir(dir);
|
||||||
const archRegex = /-(linux|darwin|windows|freebsd)-(amd64|arm64|arm|386)\.(so|dll|dylib)$/i;
|
const archRegex = /-(linux|darwin|windows|freebsd)-(amd64|arm64|arm|386)\.(so|dll|dylib)$/i;
|
||||||
|
|
||||||
const found = files.find((f) => {
|
const found = files.find((f: string) => {
|
||||||
const m = f.match(archRegex);
|
const m = f.match(archRegex);
|
||||||
if (m) {
|
if (m) {
|
||||||
return (
|
return (
|
||||||
@@ -733,3 +740,38 @@ function derivePlatformKey(filename: string): string {
|
|||||||
if (lower.endsWith(".so")) return "linux-amd64";
|
if (lower.endsWith(".so")) return "linux-amd64";
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyConfiguredNativeBinaries(
|
||||||
|
binariesMap: Record<string, string>,
|
||||||
|
config: any,
|
||||||
|
nativeBinaries: Map<string, Buffer>,
|
||||||
|
): void {
|
||||||
|
if (config?.binaries && typeof config.binaries === "object") {
|
||||||
|
for (const [platformKey, filename] of Object.entries(config.binaries)) {
|
||||||
|
if (typeof platformKey !== "string" || typeof filename !== "string") continue;
|
||||||
|
const base = path.basename(filename);
|
||||||
|
if (!nativeBinaries.has(base)) continue;
|
||||||
|
binariesMap[platformKey.toLowerCase()] = base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof config?.binary === "string" && config.binary) {
|
||||||
|
const base = path.basename(config.binary);
|
||||||
|
if (!nativeBinaries.has(base)) return;
|
||||||
|
const platformKey = derivePlatformKey(base);
|
||||||
|
if (platformKey) {
|
||||||
|
binariesMap[platformKey] = base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function nativeBinaryPriority(filename: string, pluginId: string): number {
|
||||||
|
const escapedId = pluginId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||||
|
if (new RegExp(`^${escapedId}-(linux|darwin|windows|freebsd)-(amd64|arm64|arm|386)\\.(so|dll|dylib)$`, "i").test(filename)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (/-(linux|darwin|windows|freebsd)-(amd64|arm64|arm|386)\.(so|dll|dylib)$/i.test(filename)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user