Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add accept: application/json header to remote signer requests and improve invalid response handling #6587

Merged
merged 23 commits into from
Apr 4, 2024
Merged
Changes from 12 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e062c15
fix: handle remote signer non "application/json" response content type
cnupy Mar 24, 2024
5f54826
Merge branch 'ChainSafe:unstable' into unstable
cnupy Mar 25, 2024
b02f666
Merge branch 'ChainSafe:unstable' into unstable
cnupy Mar 26, 2024
657caab
Merge branch 'ChainSafe:unstable' into unstable
cnupy Mar 27, 2024
ecdcc6a
restrict logger to minimal set and remove cast
cnupy Mar 27, 2024
383b07b
Fix typo - `minamal`; refactor/inline response handling functions; re…
cnupy Mar 27, 2024
23ca7ba
fix: exception message text
cnupy Mar 27, 2024
8ce75ab
Removed logger in externalSignerClient; Improved handling of response…
cnupy Mar 28, 2024
22f7131
fix: use response statusText as error message if response body is emp…
cnupy Mar 28, 2024
6791ae3
fix: exception message text proper epmpty string check
cnupy Mar 28, 2024
f36052c
fix: exception message text proper epmpty string check
cnupy Mar 28, 2024
6742089
fix: lint errors
cnupy Mar 29, 2024
282cc86
reintroduce handleExternalSignerResponse generic function with better…
cnupy Apr 4, 2024
94580d5
Merge branch 'ChainSafe:unstable' into unstable
cnupy Apr 4, 2024
2b8e722
fix: remove forgotten check in externalSignerUpCheck function
cnupy Apr 4, 2024
2696ea8
Simplify checking response media type
nflaig Apr 4, 2024
12b7bd9
Include json parse error message in thrown Error
nflaig Apr 4, 2024
4364c8b
Remove unnecessary string cast of err body
nflaig Apr 4, 2024
bec5c5b
Fix json parsing
nflaig Apr 4, 2024
c3f1aa3
More robust error handling
nflaig Apr 4, 2024
3100d07
Formatting
nflaig Apr 4, 2024
127909d
Simplify err body message parser
nflaig Apr 4, 2024
facf88c
Revert error handling changes
nflaig Apr 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 85 additions & 10 deletions packages/validator/src/util/externalSignerClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,12 @@ export async function externalSignerGetKeys(externalSignerUrl: string): Promise<
headers: {"Content-Type": "application/json"},
});

return handlerExternalSignerResponse<string[]>(res);
if (!res.ok) {
throw Error(`${(await res.text()) || res.statusText}`);
}

ensureCorrectWireFormat(res, WireFormat.json);
return JSON.parse(await res.text()) as string[];
}

/**
Expand Down Expand Up @@ -147,8 +152,20 @@ export async function externalSignerPostSignature(
body: JSON.stringify(requestObj),
});

const data = await handlerExternalSignerResponse<{signature: string}>(res);
return data.signature;
if (!res.ok) {
throw Error(`${(await res.text()) || res.statusText}`);
}

const resBody = await res.text();

switch (ensureCorrectWireFormat(res)) {
case WireFormat.json: {
const data = JSON.parse(resBody) as {signature: string};
return data.signature;
}
case WireFormat.text:
return resBody;
}
}

/**
Expand All @@ -160,17 +177,75 @@ export async function externalSignerUpCheck(remoteUrl: string): Promise<boolean>
headers: {"Content-Type": "application/json"},
});

const data = await handlerExternalSignerResponse<{status: string}>(res);
return data.status === "OK";
if (!res.ok) {
throw Error(`${(await res.text()) || res.statusText}`);
}

const resBody = await res.text();

switch (ensureCorrectWireFormat(res)) {
case WireFormat.json: {
const data = JSON.parse(resBody) as {status: string};
return data.status === "OK";
}
case WireFormat.text:
return resBody === "OK";
}
}

async function handlerExternalSignerResponse<T>(res: Response): Promise<T> {
if (!res.ok) {
const errBody = await res.text();
throw Error(`${errBody}`);
function ensureCorrectWireFormat(response: Response, onlySupport?: WireFormat): WireFormat {
const contentType = response.headers.get("content-type");
if (contentType === null) {
jeluard marked this conversation as resolved.
Show resolved Hide resolved
throw Error("No Content-Type header found in response");
}

const mediaType = parseContentTypeHeader(contentType);
if (mediaType === null) {
throw Error(`Unsupported response media type: ${contentType.split(";", 1)[0]}`);
}

return JSON.parse(await res.text()) as T;
const wireFormat = getWireFormat(mediaType);

if (onlySupport !== undefined && wireFormat !== onlySupport) {
throw Error(`Method only supports ${onlySupport} responses`);
}

return wireFormat;
}

enum WireFormat {
json = "json",
text = "text",
}

enum MediaType {
json = "application/json",
text = "text/plain",
}

function getWireFormat(mediaType: MediaType): WireFormat {
switch (mediaType) {
case MediaType.json:
return WireFormat.json;
case MediaType.text:
return WireFormat.text;
}
}

const supportedMediaTypes = Object.values(MediaType);

function isSupportedMediaType(mediaType: string | null): mediaType is MediaType {
return mediaType !== null && supportedMediaTypes.includes(mediaType as MediaType);
}

function parseContentTypeHeader(contentType?: string): MediaType | null {
if (!contentType) {
return null;
}

const mediaType = contentType.split(";", 1)[0].trim().toLowerCase();

return isSupportedMediaType(mediaType) ? mediaType : null;
}

function serializerSignableMessagePayload(config: BeaconConfig, payload: SignableMessage): Record<string, unknown> {
Expand Down
Loading