fix: skip password confirmation for OAuth users

OAuth users don't have passwords set, so they should not be prompted for password confirmation when performing destructive actions. This fix:
- Detects OAuth users via the hasPassword() method
- Skips password confirmation in modal for OAuth users
- Keeps text name confirmation as the final step
- Centralizes logic in helper functions for maintainability
- Changes button text to "Confirm" when password step is skipped

Fixes #4457

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2025-12-12 14:12:02 +01:00
parent 366ff95893
commit b0d50669b1
16 changed files with 109 additions and 120 deletions

View File

@@ -29,17 +29,23 @@
@php
use App\Models\InstanceSettings;
// Global setting to disable ALL two-step confirmation (text + password)
$disableTwoStepConfirmation = data_get(InstanceSettings::get(), 'disable_two_step_confirmation');
// Skip ONLY password confirmation for OAuth users (they have no password)
$skipPasswordConfirmation = shouldSkipPasswordConfirmation();
if ($temporaryDisableTwoStepConfirmation) {
$disableTwoStepConfirmation = false;
$skipPasswordConfirmation = false;
}
// When password step is skipped, Step 2 becomes final - change button text from "Continue" to "Confirm"
$effectiveStep2ButtonText = ($skipPasswordConfirmation && $step2ButtonText === 'Continue') ? 'Confirm' : $step2ButtonText;
@endphp
<div {{ $ignoreWire ? 'wire:ignore' : '' }} x-data="{
modalOpen: false,
step: {{ empty($checkboxes) ? 2 : 1 }},
initialStep: {{ empty($checkboxes) ? 2 : 1 }},
finalStep: {{ $confirmWithPassword && !$disableTwoStepConfirmation ? 3 : 2 }},
finalStep: {{ $confirmWithPassword && !$skipPasswordConfirmation ? 3 : 2 }},
deleteText: '',
password: '',
actions: @js($actions),
@@ -50,7 +56,7 @@
})(),
userConfirmationText: '',
confirmWithText: @js($confirmWithText && !$disableTwoStepConfirmation),
confirmWithPassword: @js($confirmWithPassword && !$disableTwoStepConfirmation),
confirmWithPassword: @js($confirmWithPassword && !$skipPasswordConfirmation),
submitAction: @js($submitAction),
dispatchAction: @js($dispatchAction),
passwordError: '',
@@ -59,6 +65,7 @@
dispatchEventType: @js($dispatchEventType),
dispatchEventMessage: @js($dispatchEventMessage),
disableTwoStepConfirmation: @js($disableTwoStepConfirmation),
skipPasswordConfirmation: @js($skipPasswordConfirmation),
resetModal() {
this.step = this.initialStep;
this.deleteText = '';
@@ -68,7 +75,7 @@
$wire.$refresh();
},
step1ButtonText: @js($step1ButtonText),
step2ButtonText: @js($step2ButtonText),
step2ButtonText: @js($effectiveStep2ButtonText),
step3ButtonText: @js($step3ButtonText),
validatePassword() {
if (this.confirmWithPassword && !this.password) {
@@ -92,10 +99,14 @@
const paramsMatch = this.submitAction.match(/\((.*?)\)/);
const params = paramsMatch ? paramsMatch[1].split(',').map(param => param.trim()) : [];
if (this.confirmWithPassword) {
params.push(this.password);
// Always pass password parameter (empty string if password confirmation is skipped)
// This ensures consistent method signature for backend Livewire methods
params.push(this.confirmWithPassword ? this.password : '');
// Only pass selectedActions if there are checkboxes with selections
if (this.selectedActions.length > 0) {
params.push(this.selectedActions);
}
params.push(this.selectedActions);
return $wire[methodName](...params)
.then(result => {
if (result === true) {
@@ -316,7 +327,7 @@
if (dispatchEvent) {
$wire.dispatch(dispatchEventType, dispatchEventMessage);
}
if (confirmWithPassword && !disableTwoStepConfirmation) {
if (confirmWithPassword && !skipPasswordConfirmation) {
step++;
} else {
modalOpen = false;
@@ -330,7 +341,7 @@
</div>
<!-- Step 3: Password confirmation -->
@if (!$disableTwoStepConfirmation)
@if (!$skipPasswordConfirmation)
<div x-show="step === 3 && confirmWithPassword">
<x-callout type="danger" title="Final Confirmation" class="mb-4">
Please enter your password to confirm this destructive action.