diff --git a/packages/keyring-eth-mpc/src/cloud.test.ts b/packages/keyring-eth-mpc/src/cloud.test.ts index 77f413acd..c0612687f 100644 --- a/packages/keyring-eth-mpc/src/cloud.test.ts +++ b/packages/keyring-eth-mpc/src/cloud.test.ts @@ -304,6 +304,14 @@ describe('cloud helpers', () => { encryptedKeyShare, backupId: 'backup-1', }); + + expect(fetchSpy).toHaveBeenCalledWith( + 'https://cloud.example/load-key-share-backup', + expect.objectContaining({ + method: 'GET', + headers: { Authorization: 'Bearer token-1' }, + }), + ); }); it('throws when loading a key share backup fails', async () => { diff --git a/packages/keyring-eth-mpc/src/cloud.ts b/packages/keyring-eth-mpc/src/cloud.ts index 6fe4d854b..93d6c24de 100644 --- a/packages/keyring-eth-mpc/src/cloud.ts +++ b/packages/keyring-eth-mpc/src/cloud.ts @@ -7,7 +7,51 @@ export type LoadKeyShareBackupResult = { }; /** - * Fetch JSON from the MPC backend, throwing on non-OK responses. + * Parse a fetch response as JSON, throwing on non-OK status. + * + * @param response - The fetch response. + * @param errorPrefix - Prefix for the thrown error message. + * @returns The parsed JSON body, or `undefined` when the response is empty. + */ +async function parseJsonResponse( + response: Response, + errorPrefix: string, +): Promise { + if (!response.ok) { + throw new Error(`${errorPrefix}: ${response.statusText}`); + } + + const text = await response.text(); + if (text.length === 0) { + return undefined as Result; + } + return JSON.parse(text) as Result; +} + +/** + * GET JSON from the MPC backend, throwing on non-OK responses. + * + * @param url - The request URL. + * @param token - Profile token sent as a Bearer header. + * @param errorPrefix - Prefix for the thrown error message. + * @returns The parsed JSON body, or `undefined` when the response is empty. + */ +async function getJson( + url: string, + token: string, + errorPrefix: string, +): Promise { + const response = await fetch(url, { + method: 'GET', + headers: { + Authorization: `Bearer ${token}`, + }, + }); + return parseJsonResponse(response, errorPrefix); +} + +/** + * POST JSON to the MPC backend, throwing on non-OK responses. * * @param url - The request URL. * @param token - Profile token sent as a Bearer header. @@ -15,12 +59,12 @@ export type LoadKeyShareBackupResult = { * @param errorPrefix - Prefix for the thrown error message. * @returns The parsed JSON body, or `undefined` when the response is empty. */ -async function postJson( +async function postJson( url: string, token: string, body: Record, errorPrefix: string, -): Promise { +): Promise { const response = await fetch(url, { method: 'POST', headers: { @@ -29,16 +73,7 @@ async function postJson( }, body: JSON.stringify(body), }); - - if (!response.ok) { - throw new Error(`${errorPrefix}: ${response.statusText}`); - } - - const text = await response.text(); - if (text.length === 0) { - return undefined as Response; - } - return JSON.parse(text) as Response; + return parseJsonResponse(response, errorPrefix); } /** @@ -225,13 +260,12 @@ export async function loadKeyShareBackup(opts: { baseURL: string; token: string; }): Promise { - const data = await postJson<{ + const data = await getJson<{ encryptedKeyShare: string; backupId: string; }>( `${opts.baseURL}/load-key-share-backup`, opts.token, - {}, 'Failed to load key share backup', ); return {