MCPcopy Index your code
hub / github.com/PatchMon/PatchMon / Disable

Method Disable

server-source-code/internal/handler/tfa.go:157–233  ·  view source on GitHub ↗

Disable handles POST /tfa/disable.

(w http.ResponseWriter, r *http.Request)

Source from the content-addressed store, hash-verified

155
156// Disable handles POST /tfa/disable.
157func (h *TfaHandler) Disable(w http.ResponseWriter, r *http.Request) {
158 userID, _ := r.Context().Value(middleware.UserIDKey).(string)
159 if userID == "" {
160 Error(w, http.StatusUnauthorized, "Unauthorized")
161 return
162 }
163
164 var req DisableRequest
165 if err := decodeJSON(r, &req); err != nil {
166 Error(w, http.StatusBadRequest, "Invalid request body")
167 return
168 }
169 if req.Password == "" {
170 Error(w, http.StatusBadRequest, "Password is required to disable TFA")
171 return
172 }
173
174 user, err := h.users.GetByID(r.Context(), userID)
175 if err != nil || user == nil {
176 Error(w, http.StatusNotFound, "User not found")
177 return
178 }
179 if !user.TfaEnabled {
180 Error(w, http.StatusBadRequest, "Two-factor authentication is not enabled for this account")
181 return
182 }
183 if user.PasswordHash == nil {
184 Error(w, http.StatusBadRequest, "Cannot disable TFA for accounts without a password (e.g., OIDC-only accounts)")
185 return
186 }
187
188 hash := strings.TrimSpace(*user.PasswordHash)
189 if err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(req.Password)); err != nil {
190 Error(w, http.StatusUnauthorized, "Invalid password")
191 return
192 }
193
194 if err := h.users.DisableTfa(r.Context(), userID); err != nil {
195 if h.log != nil {
196 h.log.Error("tfa disable", "error", err)
197 }
198 Error(w, http.StatusInternalServerError, "Failed to disable two-factor authentication")
199 return
200 }
201 // All trusted-device records exist solely to skip MFA. With MFA disabled they
202 // have no purpose and should not linger if the user re-enables MFA later.
203 if h.trustedDevices != nil {
204 if err := h.trustedDevices.RevokeAllForUser(r.Context(), userID); err != nil && h.log != nil {
205 h.log.Error("tfa disable revoke trusted devices failed", "user_id", userID, "error", err)
206 }
207 }
208 clearDeviceTrustCookie(w, r)
209
210 // Emit user_tfa_disabled event
211 if h.notify != nil {
212 if d := h.db.DB(r.Context()); d != nil {
213 h.notify.EmitEvent(r.Context(), d, hostctx.TenantHostKey(r.Context()), notifications.Event{
214 Type: "user_tfa_disabled",

Callers

nothing calls this directly

Calls 11

ErrorFunction · 0.85
decodeJSONFunction · 0.85
clearDeviceTrustCookieFunction · 0.85
ErrorMethod · 0.80
EmitEventMethod · 0.80
JSONFunction · 0.70
DisableTfaMethod · 0.65
DBMethod · 0.65
ValueMethod · 0.45
GetByIDMethod · 0.45
RevokeAllForUserMethod · 0.45

Tested by

no test coverage detected