diff --git a/lib/web/git_servers.go b/lib/web/git_servers.go index e31beed4d23e6..c871e5d889af1 100644 --- a/lib/web/git_servers.go +++ b/lib/web/git_servers.go @@ -93,5 +93,5 @@ func (h *Handler) gitServerDelete(_ http.ResponseWriter, r *http.Request, p http return nil, trace.Wrap(err) } - return nil, clt.GitServerClient().DeleteGitServer(r.Context(), name) + return OK(), clt.GitServerClient().DeleteGitServer(r.Context(), name) } diff --git a/lib/web/userevent.go b/lib/web/userevent.go index 46c483cc07d9d..4a11c1000180c 100644 --- a/lib/web/userevent.go +++ b/lib/web/userevent.go @@ -57,7 +57,7 @@ func (h *Handler) createPreUserEventHandle(w http.ResponseWriter, r *http.Reques return nil, trace.Wrap(err) } - return nil, nil + return OK(), nil } // createUserEventHandle sends a user event to the UserEvent service @@ -91,5 +91,5 @@ func (h *Handler) createUserEventHandle(w http.ResponseWriter, r *http.Request, return nil, trace.Wrap(err) } - return nil, nil + return OK(), nil } diff --git a/web/packages/teleport/src/services/api/api.test.ts b/web/packages/teleport/src/services/api/api.test.ts index 5616df264c662..3db7c29f1203e 100644 --- a/web/packages/teleport/src/services/api/api.test.ts +++ b/web/packages/teleport/src/services/api/api.test.ts @@ -78,6 +78,14 @@ describe('api.fetch', () => { }); }); + test('no json in response', async () => { + jest.spyOn(global, 'fetch').mockResolvedValue({ ok: true } as Response); + const resp = await api.fetch('/something'); + expect(mockedFetch).toHaveBeenCalledTimes(1); + + expect(resp).toStrictEqual({ ok: true }); + }); + test('with customOptions', async () => { await api.fetch('/something', customOpts); expect(mockedFetch).toHaveBeenCalledTimes(1); diff --git a/web/packages/teleport/src/services/api/api.ts b/web/packages/teleport/src/services/api/api.ts index ac386c641f6a4..1748518cca91b 100644 --- a/web/packages/teleport/src/services/api/api.ts +++ b/web/packages/teleport/src/services/api/api.ts @@ -151,18 +151,56 @@ const api = { mfaResponse?: MfaChallengeResponse ): Promise { try { - return await api.fetch(url, customOptions, mfaResponse); + const response = await api.fetch(url, customOptions, mfaResponse); + return await api.getJsonFromFetchResponse(response); } catch (err) { // Retry with MFA if we get an admin action MFA error. if (!mfaResponse && isAdminActionRequiresMfaError(err)) { mfaResponse = await api.getAdminActionMfaResponse(); - return api.fetch(url, customOptions, mfaResponse); + const response = await api.fetch(url, customOptions, mfaResponse); + return await api.getJsonFromFetchResponse(response); } else { throw err; } } }, + async getJsonFromFetchResponse(response: Response) { + let json; + try { + json = await response.json(); + } catch (err) { + // error reading JSON + const message = response.ok + ? err.message + : `${response.status} - ${response.url}`; + throw new ApiError({ message, response, opts: { cause: err } }); + } + + if (response.ok) { + return json; + } + + /** This error can occur in the edge case where a role in the user's certificate was deleted during their session. */ + const isRoleNotFoundErr = isRoleNotFoundError(parseError(json)); + if (isRoleNotFoundErr) { + websession.logoutWithoutSlo({ + /* Don't remember location after login, since they may no longer have access to the page they were on. */ + rememberLocation: false, + /* Show "access changed" notice on login page. */ + withAccessChangedMessage: true, + }); + return; + } + + throw new ApiError({ + message: parseError(json), + response, + proxyVersion: parseProxyVersion(json), + messages: json.messages, + }); + }, + async getAdminActionMfaResponse() { const challenge = await auth.getMfaChallenge({ scope: MfaChallengeScope.ADMIN_ACTION, @@ -218,12 +256,14 @@ const api = { * * @param mfaResponse if defined (eg: `fetchJsonWithMfaAuthnRetry`) * will add a custom MFA header field that will hold the mfaResponse. + * + * @returns the native fetch's response object. */ async fetch( url: string, customOptions: RequestInit = {}, mfaResponse?: MfaChallengeResponse - ) { + ): Promise { url = window.location.origin + url; const options = { ...defaultRequestOptions, @@ -245,41 +285,7 @@ const api = { } // native call - const response = await fetch(url, options); - - let json; - try { - json = await response.json(); - } catch (err) { - // error reading JSON - const message = response.ok - ? err.message - : `${response.status} - ${response.url}`; - throw new ApiError({ message, response, opts: { cause: err } }); - } - - if (response.ok) { - return json; - } - - /** This error can occur in the edge case where a role in the user's certificate was deleted during their session. */ - const isRoleNotFoundErr = isRoleNotFoundError(parseError(json)); - if (isRoleNotFoundErr) { - websession.logoutWithoutSlo({ - /* Don't remember location after login, since they may no longer have access to the page they were on. */ - rememberLocation: false, - /* Show "access changed" notice on login page. */ - withAccessChangedMessage: true, - }); - return; - } - - throw new ApiError({ - message: parseError(json), - response, - proxyVersion: parseProxyVersion(json), - messages: json.messages, - }); + return await fetch(url, options); }, };