diff --git a/src/components/auth/PasswordVerificationDialog.tsx b/src/components/auth/PasswordVerificationDialog.tsx deleted file mode 100644 index d59fe4c0..00000000 --- a/src/components/auth/PasswordVerificationDialog.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import { useState } from "react"; -import { Button } from "@/components/ui/button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { reverifyPasswordAuth } from "@/lib/identityService"; -import { toast } from "sonner"; -import { Loader2, AlertCircle } from "lucide-react"; -import { Alert, AlertDescription } from "@/components/ui/alert"; - -interface PasswordVerificationDialogProps { - open: boolean; - onOpenChange: (open: boolean) => void; - onSuccess: () => void; - defaultEmail?: string; -} - -export function PasswordVerificationDialog({ - open, - onOpenChange, - onSuccess, - defaultEmail = "", -}: PasswordVerificationDialogProps) { - const [email, setEmail] = useState(defaultEmail); - const [password, setPassword] = useState(""); - const [isVerifying, setIsVerifying] = useState(false); - const [showResetOption, setShowResetOption] = useState(false); - - const handleVerify = async (e: React.FormEvent) => { - e.preventDefault(); - - if (!email || !password) { - toast.error("Please enter both email and password"); - return; - } - - setIsVerifying(true); - setShowResetOption(false); - - try { - const result = await reverifyPasswordAuth(email, password); - - if (result.success) { - if (result.needsEmailConfirmation) { - toast.success("Password Verified!", { - description: "Check your email for a confirmation link to complete activation.", - duration: 8000, - }); - } else { - toast.success("Password Verified!", { - description: "Your password authentication has been activated.", - }); - } - onOpenChange(false); - onSuccess(); - } else { - setShowResetOption(true); - toast.error("Verification Failed", { - description: result.error || "Unable to verify password. Try the password reset option below.", - }); - } - } catch (error: any) { - setShowResetOption(true); - toast.error("Verification Error", { - description: error.message || "An unexpected error occurred.", - }); - } finally { - setIsVerifying(false); - } - }; - - const handlePasswordReset = () => { - onOpenChange(false); - // Navigate or trigger password reset flow - window.location.href = `/auth?email=${encodeURIComponent(email)}&message=reset-password`; - }; - - return ( - - - - Verify Password Access - - Enter your email and password to activate password authentication for your account. - - - -
-
-
- - setEmail(e.target.value)} - placeholder="your@email.com" - disabled={isVerifying} - required - /> -
- -
- - setPassword(e.target.value)} - placeholder="Enter your password" - disabled={isVerifying} - required - /> -
- - {showResetOption && ( - - - - Can't remember your password?{" "} - - - - )} -
- - - - - -
-
-
- ); -} diff --git a/src/components/settings/SecurityTab.tsx b/src/components/settings/SecurityTab.tsx index 58d39899..d59dddbc 100644 --- a/src/components/settings/SecurityTab.tsx +++ b/src/components/settings/SecurityTab.tsx @@ -17,17 +17,16 @@ import { checkDisconnectSafety, disconnectIdentity, connectIdentity, - hasOrphanedPassword + hasOrphanedPassword, + triggerOrphanedPasswordConfirmation } from '@/lib/identityService'; import type { UserIdentity, OAuthProvider } from '@/types/identity'; -import { PasswordVerificationDialog } from '@/components/auth/PasswordVerificationDialog'; import { toast as sonnerToast } from 'sonner'; export function SecurityTab() { const { user } = useAuth(); const { toast } = useToast(); const navigate = useNavigate(); const [passwordDialogOpen, setPasswordDialogOpen] = useState(false); - const [verificationDialogOpen, setVerificationDialogOpen] = useState(false); const [identities, setIdentities] = useState([]); const [loadingIdentities, setLoadingIdentities] = useState(true); const [disconnectingProvider, setDisconnectingProvider] = useState(null); @@ -48,6 +47,13 @@ export function SecurityTab() { const isOrphaned = await hasOrphanedPassword(); setShowOrphanedPasswordOption(isOrphaned); + if (isOrphaned) { + sonnerToast.info("Password Authentication Needs Activation", { + description: "Click 'Send Confirmation Email' below to complete your password setup.", + duration: 10000, + }); + } + if (isOrphaned) { sonnerToast.info("Password Authentication Needs Activation", { description: "Click 'Verify Password Access' to complete your password setup.", @@ -187,17 +193,25 @@ export function SecurityTab() { setPasswordSetupProvider('google' as OAuthProvider); }; - const handleVerifyExistingPassword = () => { - setVerificationDialogOpen(true); - }; - - const handleVerificationSuccess = async () => { - // Don't reload identities immediately - user needs to confirm email first - toast({ - title: "Email Confirmation Required", - description: "Check your email and click the confirmation link to activate password authentication.", - duration: 0, // Persistent - }); + const handleSendConfirmationEmail = async () => { + setAddingPassword(true); + + const result = await triggerOrphanedPasswordConfirmation(); + + if (result.success) { + sonnerToast.success("Confirmation Email Sent!", { + description: "Check your email for a confirmation link to activate your password authentication.", + duration: 15000, + }); + } else { + toast({ + title: "Failed to Send Email", + description: result.error, + variant: "destructive" + }); + } + + setAddingPassword(false); }; // Get connected accounts with identity data @@ -236,13 +250,6 @@ export function SecurityTab() { /> )} - -
{/* Password Section - Conditional based on auth method */}
@@ -282,10 +289,21 @@ export function SecurityTab() { {showOrphanedPasswordOption && ( )} diff --git a/src/lib/identityService.ts b/src/lib/identityService.ts index 72349c3f..a861851d 100644 --- a/src/lib/identityService.ts +++ b/src/lib/identityService.ts @@ -290,57 +290,42 @@ export async function hasOrphanedPassword(): Promise { } /** - * Re-verify password authentication by signing in and triggering email confirmation - * This creates the missing email identity through Supabase's confirmation flow + * Trigger email confirmation for orphaned password + * Direct trigger without requiring password re-entry */ -export async function reverifyPasswordAuth( - email: string, - password: string -): Promise { +export async function triggerOrphanedPasswordConfirmation(): Promise { try { - // Step 1: Verify credentials by signing in - console.log('[IdentityService] Verifying password credentials'); - const { data: authData, error: signInError } = await supabase.auth.signInWithPassword({ - email, - password - }); + const { data: { user } } = await supabase.auth.getUser(); - if (signInError) { + if (!user?.email) { return { success: false, - error: 'Invalid email or password' + error: 'No email found for current user' }; } - // Step 2: Trigger email confirmation to create identity - console.log('[IdentityService] Credentials verified, triggering email confirmation'); - const { error: updateError } = await supabase.auth.updateUser({ - email: email // Re-confirming email triggers identity creation + console.log('[IdentityService] Triggering email confirmation for orphaned password'); + + const { error } = await supabase.auth.updateUser({ + email: user.email }); - if (updateError) throw updateError; + if (error) throw error; - // Step 3: Sign out so user can confirm email - console.log('[IdentityService] Signing out to complete email confirmation'); - await supabase.auth.signOut(); - - // Step 4: Log the verification - if (authData.user) { - await logIdentityChange(authData.user.id, 'password_verified', { - method: 'orphaned_password_recovery' - }); - } + await logIdentityChange(user.id, 'orphaned_password_confirmation_triggered', { + method: 'manual_button_click' + }); return { success: true, needsEmailConfirmation: true, - email + email: user.email }; } catch (error: any) { - console.error('[IdentityService] Failed to verify password:', error); + console.error('[IdentityService] Failed to trigger confirmation:', error); return { success: false, - error: error.message || 'Failed to verify password authentication' + error: error.message || 'Failed to trigger email confirmation' }; } }