mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-03 05:00:25 +00:00
[codex] harden clawhub plugin publishing and install (#56870)
* fix: harden clawhub plugin publishing and install * fix(process): preserve windows shim exit success
This commit is contained in:
@@ -1,88 +1,7 @@
|
||||
import crypto from "node:crypto";
|
||||
import { mkdtemp, rm } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js";
|
||||
|
||||
export { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js";
|
||||
|
||||
function sanitizePrefix(prefix: string): string {
|
||||
const normalized = prefix.replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
||||
return normalized || "tmp";
|
||||
}
|
||||
|
||||
function sanitizeExtension(extension?: string): string {
|
||||
if (!extension) {
|
||||
return "";
|
||||
}
|
||||
const normalized = extension.startsWith(".") ? extension : `.${extension}`;
|
||||
const suffix = normalized.match(/[a-zA-Z0-9._-]+$/)?.[0] ?? "";
|
||||
const token = suffix.replace(/^[._-]+/, "");
|
||||
if (!token) {
|
||||
return "";
|
||||
}
|
||||
return `.${token}`;
|
||||
}
|
||||
|
||||
function sanitizeFileName(fileName: string): string {
|
||||
const base = path.basename(fileName).replace(/[^a-zA-Z0-9._-]+/g, "-");
|
||||
const normalized = base.replace(/^-+|-+$/g, "");
|
||||
return normalized || "download.bin";
|
||||
}
|
||||
|
||||
function resolveTempRoot(tmpDir?: string): string {
|
||||
return tmpDir ?? resolvePreferredOpenClawTmpDir();
|
||||
}
|
||||
|
||||
function isNodeErrorWithCode(err: unknown, code: string): boolean {
|
||||
return (
|
||||
typeof err === "object" &&
|
||||
err !== null &&
|
||||
"code" in err &&
|
||||
(err as { code?: string }).code === code
|
||||
);
|
||||
}
|
||||
|
||||
/** Build a unique temp file path with sanitized prefix/extension parts. */
|
||||
export function buildRandomTempFilePath(params: {
|
||||
prefix: string;
|
||||
extension?: string;
|
||||
tmpDir?: string;
|
||||
now?: number;
|
||||
uuid?: string;
|
||||
}): string {
|
||||
const prefix = sanitizePrefix(params.prefix);
|
||||
const extension = sanitizeExtension(params.extension);
|
||||
const nowCandidate = params.now;
|
||||
const now =
|
||||
typeof nowCandidate === "number" && Number.isFinite(nowCandidate)
|
||||
? Math.trunc(nowCandidate)
|
||||
: Date.now();
|
||||
const uuid = params.uuid?.trim() || crypto.randomUUID();
|
||||
return path.join(resolveTempRoot(params.tmpDir), `${prefix}-${now}-${uuid}${extension}`);
|
||||
}
|
||||
|
||||
/** Create a temporary download directory, run the callback, then clean it up best-effort. */
|
||||
export async function withTempDownloadPath<T>(
|
||||
params: {
|
||||
prefix: string;
|
||||
fileName?: string;
|
||||
tmpDir?: string;
|
||||
},
|
||||
fn: (tmpPath: string) => Promise<T>,
|
||||
): Promise<T> {
|
||||
const tempRoot = resolveTempRoot(params.tmpDir);
|
||||
const prefix = `${sanitizePrefix(params.prefix)}-`;
|
||||
const dir = await mkdtemp(path.join(tempRoot, prefix));
|
||||
const tmpPath = path.join(dir, sanitizeFileName(params.fileName ?? "download.bin"));
|
||||
try {
|
||||
return await fn(tmpPath);
|
||||
} finally {
|
||||
try {
|
||||
await rm(dir, { recursive: true, force: true });
|
||||
} catch (err) {
|
||||
if (!isNodeErrorWithCode(err, "ENOENT")) {
|
||||
console.warn(`temp-path cleanup failed for ${dir}: ${String(err)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export {
|
||||
buildRandomTempFilePath,
|
||||
createTempDownloadTarget,
|
||||
resolvePreferredOpenClawTmpDir,
|
||||
sanitizeTempFileName,
|
||||
withTempDownloadPath,
|
||||
} from "../infra/temp-download.js";
|
||||
|
||||
Reference in New Issue
Block a user