fix: prevent parsing CLI errors without metadata

When parsing a CLI error, check if any metadata from grpc is present before trying to parse it.
Closes #2516
This commit is contained in:
Giacomo Cusinato 2024-09-26 17:01:45 +02:00 committed by per1234
parent 91bb75ca97
commit 4a3abf542c

View File

@ -6,7 +6,7 @@ import { ProgrammerIsRequiredForUploadError } from './cli-protocol/cc/arduino/cl
type ProtoError = typeof ProgrammerIsRequiredForUploadError; type ProtoError = typeof ProgrammerIsRequiredForUploadError;
const protoErrorsMap = new Map<string, ProtoError>([ const protoErrorsMap = new Map<string, ProtoError>([
[ [
'type.googleapis.com/cc.arduino.cli.commands.v1.ProgrammerIsRequiredForUploadError', 'cc.arduino.cli.commands.v1.ProgrammerIsRequiredForUploadError',
ProgrammerIsRequiredForUploadError, ProgrammerIsRequiredForUploadError,
], ],
// handle other cli defined errors here // handle other cli defined errors here
@ -22,30 +22,33 @@ export namespace ServiceError {
return arg instanceof Error && isStatusObject(arg); return arg instanceof Error && isStatusObject(arg);
} }
export function isInstanceOf(arg: unknown, type: unknown): boolean { export function isInstanceOf<ProtoError>(
arg: unknown,
type: new (...args: unknown[]) => ProtoError
): arg is ProtoError {
if (!isStatusObject(arg)) { if (!isStatusObject(arg)) {
return false; return false;
} }
const bin = arg.metadata.get('grpc-status-details-bin')[0]; try {
const bin = arg.metadata.get('grpc-status-details-bin')[0];
const uint8Array =
typeof bin === 'string'
? stringToUint8Array(bin)
: new Uint8Array(bin.buffer, bin.byteOffset, bin.byteLength);
const uint8Array = const errors = Status.deserializeBinary(uint8Array)
typeof bin === 'string' .getDetailsList()
? stringToUint8Array(bin) .map((details) => {
: new Uint8Array(bin.buffer, bin.byteOffset, bin.byteLength); const typeName = details.getTypeName();
const ErrorType = protoErrorsMap.get(typeName);
return ErrorType?.deserializeBinary(details.getValue_asU8());
});
const errors = Status.deserializeBinary(uint8Array) return !!errors.find((error) => error && error instanceof type);
.getDetailsList() } catch {
.map((details) => { return false;
const typeUrl = details.getTypeUrl(); }
const ErrorType = protoErrorsMap.get(typeUrl);
return ErrorType?.deserializeBinary(details.getValue_asU8());
});
return !!errors.find((error) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return error && error instanceof <any>type;
});
} }
function isStatusObject(arg: unknown): arg is StatusObject { function isStatusObject(arg: unknown): arg is StatusObject {