Changed 2fa delete from body to query for code

as per best practices
This commit is contained in:
Jamie Curnow
2026-01-14 13:24:38 +10:00
parent d33bb02c74
commit c1ad7788f1
5 changed files with 28 additions and 56 deletions

View File

@@ -370,16 +370,16 @@ router
})
/**
* DELETE /api/users/123/2fa
* DELETE /api/users/123/2fa?code=XXXXXX
*
* Disable 2FA for a user
*/
.delete(async (req, res, next) => {
try {
const { code } = await apiValidator(
getValidationSchema("/users/{userID}/2fa", "delete"),
req.body,
);
const code = typeof req.query.code === "string" ? req.query.code : null;
if (!code) {
throw new errs.ValidationError("Missing required parameter: code");
}
await internal2FA.disable(res.locals.access, req.params.user_id, code);
res.status(200).send(true);
} catch (err) {

View File

@@ -13,32 +13,21 @@
"required": true,
"description": "User ID",
"example": 2
},
{
"in": "query",
"name": "code",
"schema": {
"type": "string",
"minLength": 6,
"maxLength": 6,
"example": "012345"
},
"required": true,
"description": "2fa Code",
"example": "012345"
}
],
"requestBody": {
"description": "2fa Code Payload",
"required": true,
"content": {
"application/json": {
"schema": {
"additionalProperties": false,
"properties": {
"code": {
"minLength": 6,
"maxLength": 6,
"type": "string",
"example": "012345"
}
},
"required": ["code"],
"type": "object"
},
"example": {
"code": "012345"
}
}
}
},
"responses": {
"200": {
"content": {

View File

@@ -27,12 +27,10 @@
"application/json": {
"examples": {
"default": {
"value": [
{
"enabled": false,
"backup_codes_remaining": 0
}
]
"value": {
"enabled": false,
"backup_codes_remaining": 0
}
}
},
"schema": {

View File

@@ -156,7 +156,6 @@ export async function del({ url, params }: DeleteArgs, abortController?: AbortCo
const method = "DELETE";
const headers = {
...buildAuthHeader(),
[contentTypeHeader]: "application/json",
};
const signal = abortController?.signal;
const response = await fetch(apiUrl, { method, headers, signal });

View File

@@ -1,5 +1,3 @@
import { camelizeKeys, decamelizeKeys } from "humps";
import AuthStore from "src/modules/AuthStore";
import * as api from "./base";
import type { TwoFactorEnableResponse, TwoFactorSetupResponse, TwoFactorStatusResponse } from "./responseTypes";
@@ -22,25 +20,13 @@ export async function enable2FA(userId: number | "me", code: string): Promise<Tw
});
}
export async function disable2FA(userId: number | "me", code: string): Promise<{ success: boolean }> {
const headers: Record<string, string> = {
"Content-Type": "application/json",
};
if (AuthStore.token) {
headers.Authorization = `Bearer ${AuthStore.token.token}`;
}
const response = await fetch(`/api/users/${userId}/2fa`, {
method: "DELETE",
headers,
body: JSON.stringify(decamelizeKeys({ code })),
export async function disable2FA(userId: number | "me", code: string): Promise<boolean> {
return await api.del({
url: `/users/${userId}/2fa`,
params: {
code,
},
});
const payload = await response.json();
if (!response.ok) {
throw new Error(payload.error?.messageI18n || payload.error?.message || "Failed to disable 2FA");
}
return camelizeKeys(payload) as { success: boolean };
}
export async function regenerateBackupCodes(userId: number | "me", code: string): Promise<TwoFactorEnableResponse> {