Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion lib/web/git_servers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Comment thread
kimlisa marked this conversation as resolved.
}
4 changes: 2 additions & 2 deletions lib/web/userevent.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
8 changes: 8 additions & 0 deletions web/packages/teleport/src/services/api/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
82 changes: 44 additions & 38 deletions web/packages/teleport/src/services/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,18 +151,56 @@ const api = {
mfaResponse?: MfaChallengeResponse
): Promise<any> {
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,
Expand Down Expand Up @@ -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<Response> {
url = window.location.origin + url;
const options = {
...defaultRequestOptions,
Expand All @@ -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);
},
};

Expand Down