mirror of
https://github.com/morluto/rea.git
synced 2026-11-10 00:36:35 +00:00
182 lines
5.3 KiB
TypeScript
182 lines
5.3 KiB
TypeScript
import type {
|
|
PyInstallerMetadata,
|
|
PyInstallerEntryMetadata,
|
|
} from "../../domain/artifactFormatMetadata.js";
|
|
import {
|
|
isCArchivePythonModule,
|
|
type CArchiveEntry,
|
|
type PyInstallerCookie,
|
|
} from "./CArchiveLayout.js";
|
|
import type { PyzArchive, PyzEntry } from "./PyzArchive.js";
|
|
|
|
const cookiePythonVersion = (value: number) =>
|
|
value >= 100
|
|
? { major: Math.floor(value / 100), minor: value % 100 }
|
|
: value >= 20
|
|
? { major: Math.floor(value / 10), minor: value % 10 }
|
|
: undefined;
|
|
|
|
export const cookieMetadata = (
|
|
cookie: PyInstallerCookie,
|
|
entries: readonly CArchiveEntry[],
|
|
encryptionMarker: boolean,
|
|
): PyInstallerMetadata => {
|
|
const version = cookiePythonVersion(cookie.pythonVersion);
|
|
return {
|
|
kind: "pyinstaller",
|
|
layout_version: cookie.layout,
|
|
archive_start: cookie.archiveStart,
|
|
archive_size: cookie.packageLength,
|
|
cookie_offset: cookie.cookieOffset,
|
|
toc_offset: cookie.tocOffset,
|
|
toc_size: cookie.tocLength,
|
|
entry_count: entries.length,
|
|
runtime_option_count: entries.filter(
|
|
(entry) => entry.role === "runtime-option",
|
|
).length,
|
|
external_dependency_count: entries.filter(
|
|
(entry) => entry.role === "dependency",
|
|
).length,
|
|
python_version_raw: cookie.pythonVersion,
|
|
python_major: version?.major ?? null,
|
|
python_minor: version?.minor ?? null,
|
|
python_library: cookie.pythonLibrary,
|
|
encryption_marker_present: encryptionMarker,
|
|
};
|
|
};
|
|
|
|
/** A sibling PYZ header is usable for scripts only when every image and the cookie agree. */
|
|
export const scriptPythonMagic = (
|
|
cookie: PyInstallerCookie,
|
|
archives: Iterable<PyzArchive>,
|
|
): Buffer | undefined => {
|
|
const version = cookiePythonVersion(cookie.pythonVersion);
|
|
if (version === undefined) return undefined;
|
|
let selected: Buffer | undefined;
|
|
for (const archive of archives) {
|
|
const magic = archive.pythonMagic;
|
|
if (
|
|
archive.pythonVersion !==
|
|
`${String(version.major)}.${String(version.minor)}` ||
|
|
(selected !== undefined && !selected.equals(magic))
|
|
)
|
|
return undefined;
|
|
selected = magic;
|
|
}
|
|
return selected;
|
|
};
|
|
|
|
const entryMetadata = (
|
|
source: Pick<
|
|
PyInstallerEntryMetadata,
|
|
| "container"
|
|
| "container_name"
|
|
| "index"
|
|
| "source_name"
|
|
| "type_code"
|
|
| "relative_offset"
|
|
| "compression_flag"
|
|
>,
|
|
bytecode: boolean,
|
|
header: Buffer | undefined,
|
|
): PyInstallerEntryMetadata => ({
|
|
kind: "pyinstaller-entry",
|
|
...source,
|
|
bytecode_header: bytecode
|
|
? header === undefined
|
|
? "unknown"
|
|
: "derived"
|
|
: "not-bytecode",
|
|
bytecode_magic: header?.subarray(0, 4).toString("hex") ?? null,
|
|
pyz_status: "not-pyz",
|
|
directory_record_offset: null,
|
|
directory_record_size: null,
|
|
pyz_sha256: null,
|
|
pyz_python_magic: null,
|
|
pyz_python_version: null,
|
|
pyz_entry_count: null,
|
|
encryption_source: null,
|
|
});
|
|
|
|
export const cArchiveEntryMetadata = (
|
|
entry: CArchiveEntry,
|
|
header?: Buffer,
|
|
archive?: PyzArchive,
|
|
encryptionMarker = false,
|
|
): PyInstallerEntryMetadata => ({
|
|
...entryMetadata(
|
|
{
|
|
container: "carchive",
|
|
container_name: null,
|
|
index: entry.index,
|
|
source_name: entry.name,
|
|
type_code: entry.typeCode,
|
|
relative_offset: entry.offset,
|
|
compression_flag: entry.compressionFlag,
|
|
},
|
|
entry.role === "script" || isCArchivePythonModule(entry),
|
|
header,
|
|
),
|
|
...(entry.role === "dependency" ? dependencyMetadata(entry.name) : {}),
|
|
pyz_status:
|
|
archive?.kind === "entries"
|
|
? "decoded"
|
|
: archive === undefined
|
|
? "not-pyz"
|
|
: "opaque",
|
|
directory_record_offset: entry.tocRecordOffset,
|
|
directory_record_size: entry.tocRecordLength,
|
|
pyz_sha256: archive?.sha256 ?? null,
|
|
pyz_python_magic: archive?.pythonMagic.toString("hex") ?? null,
|
|
pyz_python_version: archive?.pythonVersion ?? null,
|
|
pyz_entry_count: archive?.kind === "entries" ? archive.entries.length : null,
|
|
encryption_source:
|
|
archive !== undefined && encryptionMarker ? "carchive-marker" : null,
|
|
});
|
|
|
|
/** The bootloader splits at the first colon; neither part is a local read grant. */
|
|
const dependencyMetadata = (
|
|
source: string,
|
|
): Pick<
|
|
PyInstallerEntryMetadata,
|
|
"dependency_status" | "dependency_archive" | "dependency_member"
|
|
> => {
|
|
const colon = source.indexOf(":");
|
|
const valid = colon > 0 && colon < source.length - 1;
|
|
return {
|
|
dependency_status: valid ? "unresolved" : "invalid-reference",
|
|
dependency_archive: valid ? source.slice(0, colon) : null,
|
|
dependency_member: valid ? source.slice(colon + 1) : null,
|
|
};
|
|
};
|
|
|
|
/** Legacy writers encrypt nonempty namespace payloads as well as module payloads. */
|
|
export const pyzEntryEncrypted = (
|
|
entry: PyzEntry,
|
|
encryptionMarker: boolean,
|
|
): boolean => encryptionMarker && entry.length > 0;
|
|
|
|
export const pyzEntryMetadata = (
|
|
container: CArchiveEntry,
|
|
entry: PyzEntry,
|
|
header: Buffer | undefined,
|
|
encryptionMarker: boolean,
|
|
): PyInstallerEntryMetadata => ({
|
|
...entryMetadata(
|
|
{
|
|
container: "pyz",
|
|
container_name: container.name,
|
|
index: entry.index,
|
|
source_name: entry.name,
|
|
type_code: entry.typeCode,
|
|
relative_offset: entry.offset,
|
|
compression_flag: entry.compressionFlag,
|
|
},
|
|
entry.role === "module" || entry.role === "package",
|
|
header,
|
|
),
|
|
encryption_source: pyzEntryEncrypted(entry, encryptionMarker)
|
|
? "carchive-marker"
|
|
: null,
|
|
});
|