import path from "node:path" ;
import { resolveSafeBaseDir } from "./path-safety.js" ;
export function isWindowsDrivePath(value: string): boolean {
return /^[a-zA-Z]:[\\/]/.test(value);
}
export function normalizeArchiveEntryPath(raw: string): string {
return raw.replaceAll("\\" , "/" );
}
export function validateArchiveEntryPath(
entryPath: string,
params?: { escapeLabel?: string },
): void {
if (!entryPath || entryPath === "." || entryPath === "./" ) {
return ;
}
if (isWindowsDrivePath(entryPath)) {
throw new Error(`archive entry uses a drive path: ${entryPath}`);
}
const normalized = path.posix.normalize(normalizeArchiveEntryPath(entryPath));
const escapeLabel = params?.escapeLabel ?? "destination" ;
if (normalized === ".." || normalized.startsWith("../" )) {
throw new Error(`archive entry escapes ${escapeLabel}: ${entryPath}`);
}
if (path.posix.isAbsolute(normalized) || normalized.startsWith("//")) {
throw new Error(`archive entry is absolute: ${entryPath}`);
}
}
export function stripArchivePath(entryPath: string, stripComponents: number): string | null {
const raw = normalizeArchiveEntryPath(entryPath);
if (!raw || raw === "." || raw === "./" ) {
return null ;
}
// Mimic tar --strip-components semantics (raw segments before normalization)
// so strip-induced escapes like "a/../b" are visible to validators.
const parts = raw.split("/" ).filter((part) => part.length > 0 && part !== "." );
const strip = Math.max(0 , Math.floor(stripComponents));
const stripped = strip === 0 ? parts.join("/" ) : parts.slice(strip).join("/" );
const result = path.posix.normalize(stripped);
if (!result || result === "." || result === "./" ) {
return null ;
}
return result;
}
export function resolveArchiveOutputPath(params: {
rootDir: string;
relPath: string;
originalPath: string;
escapeLabel?: string;
}): string {
const safeBase = resolveSafeBaseDir(params.rootDir);
const outPath = path.resolve(params.rootDir, params.relPath);
const escapeLabel = params.escapeLabel ?? "destination" ;
if (!outPath.startsWith(safeBase)) {
throw new Error(`archive entry escapes ${escapeLabel}: ${params.originalPath}`);
}
return outPath;
}
Messung V0.5 in Prozent C=96 H=100 G=97
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-09)
¤
*© Formatika GbR, Deutschland