diff --git a/backend/routes/users.js b/backend/routes/users.js index 23e75862..7c3da8c1 100644 --- a/backend/routes/users.js +++ b/backend/routes/users.js @@ -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) { diff --git a/backend/schema/paths/users/userID/2fa/delete.json b/backend/schema/paths/users/userID/2fa/delete.json index d308be7f..bff292d8 100644 --- a/backend/schema/paths/users/userID/2fa/delete.json +++ b/backend/schema/paths/users/userID/2fa/delete.json @@ -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": { diff --git a/backend/schema/paths/users/userID/2fa/get.json b/backend/schema/paths/users/userID/2fa/get.json index ff8f9d4a..78ce1886 100644 --- a/backend/schema/paths/users/userID/2fa/get.json +++ b/backend/schema/paths/users/userID/2fa/get.json @@ -27,12 +27,10 @@ "application/json": { "examples": { "default": { - "value": [ - { - "enabled": false, - "backup_codes_remaining": 0 - } - ] + "value": { + "enabled": false, + "backup_codes_remaining": 0 + } } }, "schema": { diff --git a/frontend/src/api/backend/base.ts b/frontend/src/api/backend/base.ts index 54eed050..d56f120c 100644 --- a/frontend/src/api/backend/base.ts +++ b/frontend/src/api/backend/base.ts @@ -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 }); diff --git a/frontend/src/api/backend/twoFactor.ts b/frontend/src/api/backend/twoFactor.ts index b50b69f1..855e9cc1 100644 --- a/frontend/src/api/backend/twoFactor.ts +++ b/frontend/src/api/backend/twoFactor.ts @@ -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 { - const headers: Record = { - "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 { + 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 {