94 lines
3.0 KiB
TypeScript
94 lines
3.0 KiB
TypeScript
import type { NpmIntegrityDrift, NpmSpecResolution } from "./install-source-utils.js";
|
|
|
|
export type NpmIntegrityDriftPayload = {
|
|
spec: string;
|
|
expectedIntegrity: string;
|
|
actualIntegrity: string;
|
|
resolution: NpmSpecResolution;
|
|
};
|
|
|
|
type ResolveNpmIntegrityDriftParams<TPayload> = {
|
|
spec: string;
|
|
expectedIntegrity?: string;
|
|
resolution: NpmSpecResolution;
|
|
createPayload: (params: {
|
|
spec: string;
|
|
expectedIntegrity: string;
|
|
actualIntegrity: string;
|
|
resolution: NpmSpecResolution;
|
|
}) => TPayload;
|
|
onIntegrityDrift?: (payload: TPayload) => boolean | Promise<boolean>;
|
|
warn?: (payload: TPayload) => void;
|
|
};
|
|
|
|
export type ResolveNpmIntegrityDriftResult<TPayload> = {
|
|
integrityDrift?: NpmIntegrityDrift;
|
|
proceed: boolean;
|
|
payload?: TPayload;
|
|
};
|
|
|
|
export async function resolveNpmIntegrityDrift<TPayload>(
|
|
params: ResolveNpmIntegrityDriftParams<TPayload>,
|
|
): Promise<ResolveNpmIntegrityDriftResult<TPayload>> {
|
|
if (!params.expectedIntegrity || !params.resolution.integrity) {
|
|
return { proceed: true };
|
|
}
|
|
if (params.expectedIntegrity === params.resolution.integrity) {
|
|
return { proceed: true };
|
|
}
|
|
|
|
const integrityDrift: NpmIntegrityDrift = {
|
|
expectedIntegrity: params.expectedIntegrity,
|
|
actualIntegrity: params.resolution.integrity,
|
|
};
|
|
const payload = params.createPayload({
|
|
spec: params.spec,
|
|
expectedIntegrity: integrityDrift.expectedIntegrity,
|
|
actualIntegrity: integrityDrift.actualIntegrity,
|
|
resolution: params.resolution,
|
|
});
|
|
|
|
let proceed = true;
|
|
if (params.onIntegrityDrift) {
|
|
proceed = await params.onIntegrityDrift(payload);
|
|
} else {
|
|
params.warn?.(payload);
|
|
}
|
|
|
|
return { integrityDrift, proceed, payload };
|
|
}
|
|
|
|
type ResolveNpmIntegrityDriftWithDefaultMessageParams = {
|
|
spec: string;
|
|
expectedIntegrity?: string;
|
|
resolution: NpmSpecResolution;
|
|
onIntegrityDrift?: (payload: NpmIntegrityDriftPayload) => boolean | Promise<boolean>;
|
|
warn?: (message: string) => void;
|
|
};
|
|
|
|
export async function resolveNpmIntegrityDriftWithDefaultMessage(
|
|
params: ResolveNpmIntegrityDriftWithDefaultMessageParams,
|
|
): Promise<{ integrityDrift?: NpmIntegrityDrift; error?: string }> {
|
|
const driftResult = await resolveNpmIntegrityDrift<NpmIntegrityDriftPayload>({
|
|
spec: params.spec,
|
|
expectedIntegrity: params.expectedIntegrity,
|
|
resolution: params.resolution,
|
|
createPayload: (drift) => ({ ...drift }),
|
|
onIntegrityDrift: params.onIntegrityDrift,
|
|
warn: (driftPayload) => {
|
|
params.warn?.(
|
|
`Integrity drift detected for ${driftPayload.resolution.resolvedSpec ?? driftPayload.spec}: expected ${driftPayload.expectedIntegrity}, got ${driftPayload.actualIntegrity}`,
|
|
);
|
|
},
|
|
});
|
|
|
|
if (!driftResult.proceed && driftResult.payload) {
|
|
return {
|
|
integrityDrift: driftResult.integrityDrift,
|
|
error: `aborted: npm package integrity drift detected for ${driftResult.payload.resolution.resolvedSpec ?? driftResult.payload.spec}`,
|
|
};
|
|
}
|
|
|
|
return { integrityDrift: driftResult.integrityDrift };
|
|
}
|