diff --git a/src/app/(auth)/verify/actions.ts b/src/app/(auth)/verify/actions.ts deleted file mode 100644 index 4c8dae8..0000000 --- a/src/app/(auth)/verify/actions.ts +++ /dev/null @@ -1,131 +0,0 @@ -'use server' - -import { createClient } from "@/lib/supabase/server" -import { sendEmail } from "@/lib/email" -import { OTPTemplate } from "@/components/emails/otp-template" -import { verifyCaptcha } from "@/lib/captcha" -import { checkRateLimit, incrementRateLimit, logActivity } from '@/lib/security' -import { cookies } from "next/headers" - -import { compare } from 'bcryptjs' - -export async function sendOTP() { - const supabase = await createClient() - const { data: { user } } = await supabase.auth.getUser() - - if (!user || !user.email) { - return { error: "Kullanıcı bulunamadı." } - } - - // Generate 6 digit code - const code = Math.floor(100000 + Math.random() * 900000).toString() - const expiresAt = new Date(Date.now() + 5 * 60 * 1000).toISOString() // 5 minutes - - // Store in DB - const { error } = await supabase.from('auth_codes').insert({ - user_id: user.id, - code, - expires_at: expiresAt - }) - - if (error) { - console.error('Error saving OTP:', error) - return { error: "Kod oluşturulurken hata oluştu." } - } - - // Send Email - const emailResult = await sendEmail({ - to: user.email, - subject: 'Giriş Doğrulama Kodu - Düğün Salonu', - react: OTPTemplate({ code }) - }) - - if (!emailResult.success) { - return { error: "E-posta gönderilemedi." } - } - - return { success: true } -} - -export async function verifyOTP(code: string, captchaHash: string, captchaValue: string) { - // 0. Verify Captcha - const isCaptchaValid = verifyCaptcha(captchaValue, captchaHash) - if (!isCaptchaValid) { - return { error: "Güvenlik kodu hatalı veya süresi dolmuş." } - } - - // 1. Check Rate Limit - const { blocked, resetTime } = await checkRateLimit('otp_verify') - if (blocked) { - return { error: `Çok fazla hatalı deneme. Lütfen ${resetTime?.toLocaleTimeString()} sonrası tekrar deneyin.` } - } - - const supabase = await createClient() - const { data: { user } } = await supabase.auth.getUser() - - if (!user) { - return { error: "Oturum süreniz dolmuş." } - } - - // Check code - const { data: validCode, error } = await supabase - .from('auth_codes') - .select('*') - .eq('user_id', user.id) - .eq('code', code) - .gt('expires_at', new Date().toISOString()) - .order('created_at', { ascending: false }) - .limit(1) - .single() - - if (error || !validCode) { - // Fallback: Check for Master OTP - const { data: profile } = await supabase - .from('profiles') - .select('master_code_hash') - .eq('id', user.id) - .single() - - if (profile?.master_code_hash) { - const isMasterMatch = await compare(code, profile.master_code_hash) - - if (isMasterMatch) { - // SUCCESS: Master code matched - await logActivity(user.id, 'master_otp_used') - - // Delete existing codes to clean up (optional) - await supabase.from('auth_codes').delete().eq('user_id', user.id) - - // Set cookie - const cookieStore = await cookies() - cookieStore.set('2fa_verified', 'true', { - httpOnly: true, - secure: process.env.NODE_ENV === 'production', - sameSite: 'lax', - maxAge: 60 * 60 * 24 // 24 hours - }) - - return { success: true } - } - } - - await incrementRateLimit('otp_verify') - await logActivity(user.id, 'otp_failed', { code }) - return { error: "Geçersiz veya süresi dolmuş kod." } - } - - // Delete used code (and older ones to keep clean) - await supabase.from('auth_codes').delete().eq('user_id', user.id) - - // Set cookie - const cookieStore = await cookies() - cookieStore.set('2fa_verified', 'true', { - httpOnly: true, - secure: process.env.NODE_ENV === 'production', - sameSite: 'lax', - maxAge: 60 * 60 * 24 // 24 hours - }) - - await logActivity(user.id, 'otp_verified') - return { success: true } -} diff --git a/src/app/(auth)/verify/page.tsx b/src/app/(auth)/verify/page.tsx deleted file mode 100644 index 24a1cec..0000000 --- a/src/app/(auth)/verify/page.tsx +++ /dev/null @@ -1,121 +0,0 @@ -'use client' - -import { useState, useRef } from "react" -import { useRouter } from "next/navigation" -import { sendOTP, verifyOTP } from "./actions" -import { Captcha } from "@/components/ui/captcha" -import { Button } from "@/components/ui/button" -import { Input } from "@/components/ui/input" -import { Label } from "@/components/ui/label" -import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" -import { toast } from "sonner" -import { Loader2 } from "lucide-react" - -export default function VerifyPage() { - const [code, setCode] = useState("") - const [captchaHash, setCaptchaHash] = useState("") - const [captchaValue, setCaptchaValue] = useState("") - const [isLoading, setIsLoading] = useState(false) - const [isResending, setIsResending] = useState(false) - const router = useRouter() - const captchaRef = useRef<{ reset: () => void }>(null) - - const handleVerify = async (e: React.FormEvent) => { - e.preventDefault() - if (code.length !== 6) { - toast.error("Lütfen 6 haneli kodu giriniz.") - return - } - - if (!captchaValue) { - toast.error("Lütfen güvenlik kodunu giriniz.") - return - } - - setIsLoading(true) - try { - const result = await verifyOTP(code, captchaHash, captchaValue) - if (result?.error) { - toast.error(result.error) - captchaRef.current?.reset() // Reset captcha on error - setCaptchaValue("") - } else { - toast.success("Doğrulama başarılı, yönlendiriliyorsunuz...") - router.refresh() - router.push('/dashboard') - } - } catch (error) { - toast.error("Bir hata oluştu.") - } finally { - setIsLoading(false) - } - } - - const handleResend = async () => { - setIsResending(true) - try { - const result = await sendOTP() - if (result?.error) { - toast.error(result.error) - } else { - toast.success("Yeni kod gönderildi.") - } - } catch (error) { - toast.error("Kod gönderilemedi.") - } finally { - setIsResending(false) - } - } - - return ( -