Skip to content

Commit c1ad778

Browse files
committed
Changed 2fa delete from body to query for code
as per best practices
1 parent d33bb02 commit c1ad778

5 files changed

Lines changed: 28 additions & 56 deletions

File tree

backend/routes/users.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -370,16 +370,16 @@ router
370370
})
371371

372372
/**
373-
* DELETE /api/users/123/2fa
373+
* DELETE /api/users/123/2fa?code=XXXXXX
374374
*
375375
* Disable 2FA for a user
376376
*/
377377
.delete(async (req, res, next) => {
378378
try {
379-
const { code } = await apiValidator(
380-
getValidationSchema("/users/{userID}/2fa", "delete"),
381-
req.body,
382-
);
379+
const code = typeof req.query.code === "string" ? req.query.code : null;
380+
if (!code) {
381+
throw new errs.ValidationError("Missing required parameter: code");
382+
}
383383
await internal2FA.disable(res.locals.access, req.params.user_id, code);
384384
res.status(200).send(true);
385385
} catch (err) {

backend/schema/paths/users/userID/2fa/delete.json

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,21 @@
1313
"required": true,
1414
"description": "User ID",
1515
"example": 2
16+
},
17+
{
18+
"in": "query",
19+
"name": "code",
20+
"schema": {
21+
"type": "string",
22+
"minLength": 6,
23+
"maxLength": 6,
24+
"example": "012345"
25+
},
26+
"required": true,
27+
"description": "2fa Code",
28+
"example": "012345"
1629
}
1730
],
18-
"requestBody": {
19-
"description": "2fa Code Payload",
20-
"required": true,
21-
"content": {
22-
"application/json": {
23-
"schema": {
24-
"additionalProperties": false,
25-
"properties": {
26-
"code": {
27-
"minLength": 6,
28-
"maxLength": 6,
29-
"type": "string",
30-
"example": "012345"
31-
}
32-
},
33-
"required": ["code"],
34-
"type": "object"
35-
},
36-
"example": {
37-
"code": "012345"
38-
}
39-
}
40-
}
41-
},
4231
"responses": {
4332
"200": {
4433
"content": {

backend/schema/paths/users/userID/2fa/get.json

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,10 @@
2727
"application/json": {
2828
"examples": {
2929
"default": {
30-
"value": [
31-
{
32-
"enabled": false,
33-
"backup_codes_remaining": 0
34-
}
35-
]
30+
"value": {
31+
"enabled": false,
32+
"backup_codes_remaining": 0
33+
}
3634
}
3735
},
3836
"schema": {

frontend/src/api/backend/base.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ export async function del({ url, params }: DeleteArgs, abortController?: AbortCo
156156
const method = "DELETE";
157157
const headers = {
158158
...buildAuthHeader(),
159-
[contentTypeHeader]: "application/json",
160159
};
161160
const signal = abortController?.signal;
162161
const response = await fetch(apiUrl, { method, headers, signal });

frontend/src/api/backend/twoFactor.ts

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { camelizeKeys, decamelizeKeys } from "humps";
2-
import AuthStore from "src/modules/AuthStore";
31
import * as api from "./base";
42
import type { TwoFactorEnableResponse, TwoFactorSetupResponse, TwoFactorStatusResponse } from "./responseTypes";
53

@@ -22,25 +20,13 @@ export async function enable2FA(userId: number | "me", code: string): Promise<Tw
2220
});
2321
}
2422

25-
export async function disable2FA(userId: number | "me", code: string): Promise<{ success: boolean }> {
26-
const headers: Record<string, string> = {
27-
"Content-Type": "application/json",
28-
};
29-
if (AuthStore.token) {
30-
headers.Authorization = `Bearer ${AuthStore.token.token}`;
31-
}
32-
33-
const response = await fetch(`/api/users/${userId}/2fa`, {
34-
method: "DELETE",
35-
headers,
36-
body: JSON.stringify(decamelizeKeys({ code })),
23+
export async function disable2FA(userId: number | "me", code: string): Promise<boolean> {
24+
return await api.del({
25+
url: `/users/${userId}/2fa`,
26+
params: {
27+
code,
28+
},
3729
});
38-
39-
const payload = await response.json();
40-
if (!response.ok) {
41-
throw new Error(payload.error?.messageI18n || payload.error?.message || "Failed to disable 2FA");
42-
}
43-
return camelizeKeys(payload) as { success: boolean };
4430
}
4531

4632
export async function regenerateBackupCodes(userId: number | "me", code: string): Promise<TwoFactorEnableResponse> {

0 commit comments

Comments
 (0)