diff --git a/next.config.ts b/next.config.ts
index 354a29b..114fa69 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -10,6 +10,12 @@ const nextConfig: NextConfig = {
port: '',
pathname: '/storage/v1/object/public/**',
},
+ {
+ protocol: 'https',
+ hostname: 'api-weeding.edoysoft.com',
+ port: '',
+ pathname: '/storage/v1/object/public/**',
+ },
{
protocol: 'https',
hostname: 'img.youtube.com',
diff --git a/src/app/(auth)/login/actions.ts b/src/app/(auth)/login/actions.ts
index 7b8a790..3649673 100644
--- a/src/app/(auth)/login/actions.ts
+++ b/src/app/(auth)/login/actions.ts
@@ -3,8 +3,7 @@
import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
import { createClient } from '@/lib/supabase/server'
-import { sendOTP } from '../verify/actions'
-import { checkRateLimit, incrementRateLimit, logActivity } from '@/lib/security'
+import { logActivity } from '@/lib/security'
export type LoginState = {
error?: string
@@ -17,30 +16,19 @@ export async function login(prevState: LoginState, formData: FormData): Promise<
const email = formData.get('email') as string
const password = formData.get('password') as string
- // 1. Check Rate Limit
- const { blocked, resetTime } = await checkRateLimit('login_attempt')
- if (blocked) {
- return { error: `Çok fazla hatalı deneme. Lütfen ${resetTime?.toLocaleTimeString()} sonrası tekrar deneyin.` }
- }
-
const { data: { user }, error } = await supabase.auth.signInWithPassword({
email,
password,
})
if (error) {
- await incrementRateLimit('login_attempt')
await logActivity(null, 'login_failed', { email, error: error.message })
return { error: 'Giriş yapılamadı. E-posta veya şifre hatalı.' }
}
await logActivity(user?.id || null, 'login_success', { email })
- revalidatePath('/', 'layout')
revalidatePath('/', 'layout')
- // Trigger OTP email
- await sendOTP()
-
- redirect('/verify')
+ redirect('/dashboard')
}
diff --git a/src/lib/captcha.ts b/src/lib/captcha.ts
deleted file mode 100644
index 86ad531..0000000
--- a/src/lib/captcha.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import { createHmac } from 'crypto'
-
-export interface CaptchaData {
- image: string // SVG string
- hash: string // HMAC hash of the text
-}
-
-const CAPTCHA_SECRET = process.env.CAPTCHA_SECRET || 'default-secret-change-me'
-
-export function generateCaptcha(width = 200, height = 80): { text: string, data: string } {
- console.log('[Captcha] Generating new captcha...')
- // 1. Generate random text (5 chars)
- const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789' // Removed confusing chars like I, 1, 0, O
- let text = ''
- for (let i = 0; i < 5; i++) {
- text += chars.charAt(Math.floor(Math.random() * chars.length))
- }
- console.log('[Captcha] Generated text:', text)
-
- // 2. Create SVG
- const bg = '#f3f4f6'
- const fg = '#374151'
-
- // Random noise lines
- let noise = ''
- for (let i = 0; i < 7; i++) {
- const x1 = Math.random() * width
- const y1 = Math.random() * height
- const x2 = Math.random() * width
- const y2 = Math.random() * height
- noise += ``
- }
-
- // Random noise dots
- for (let i = 0; i < 30; i++) {
- const x = Math.random() * width
- const y = Math.random() * height
- noise += ``
- }
-
- // Text with slight rotation/position randomization
- let svgText = ''
- const fontSize = 32
- const startX = 20
- const spacing = 35
-
- for (let i = 0; i < text.length; i++) {
- const char = text[i]
- const x = startX + (i * spacing) + (Math.random() * 10 - 5)
- const y = (height / 2) + (fontSize / 3) + (Math.random() * 10 - 5)
- const rotate = Math.random() * 40 - 20 // +/- 20 degrees
-
- svgText += `${char}`
- }
-
- const svg = `
-`
-
- return { text, data: svg }
-}
-
-export function signCaptcha(text: string): string {
- const expires = Date.now() + 5 * 60 * 1000 // 5 minutes
- const data = `${text.toUpperCase()}|${expires}`
- const signature = createHmac('sha256', CAPTCHA_SECRET).update(data).digest('hex')
- return `${data}|${signature}`
-}
-
-export function verifyCaptcha(input: string, hash: string): boolean {
- if (!input || !hash) {
- console.log('[Captcha] Missing input or hash')
- return false
- }
-
- const parts = hash.split('|')
- if (parts.length !== 3) {
- console.log('[Captcha] Invalid hash format')
- return false
- }
-
- const [originalText, expiresStr, signature] = parts
- const expires = parseInt(expiresStr, 10)
-
- // Check expiration
- if (Date.now() > expires) {
- console.log('[Captcha] Expired. Now:', Date.now(), 'Expires:', expires)
- return false
- }
-
- // Check signature integrity
- const expectedData = `${originalText}|${expiresStr}`
- const expectedSignature = createHmac('sha256', CAPTCHA_SECRET).update(expectedData).digest('hex')
-
- if (signature !== expectedSignature) {
- console.log('[Captcha] Signature mismatch')
- return false
- }
-
- // Check content match
- const isValid = input.toUpperCase() === originalText
- if (!isValid) {
- console.log('[Captcha] Text mismatch. Expected:', originalText, 'Got:', input.toUpperCase())
- }
- return isValid
-}
diff --git a/src/lib/security.ts b/src/lib/security.ts
index ee3cbb2..31050e4 100644
--- a/src/lib/security.ts
+++ b/src/lib/security.ts
@@ -33,100 +33,4 @@ export async function logActivity(
}
}
-export async function checkRateLimit(action: string): Promise<{ blocked: boolean, remaining?: number, resetTime?: Date }> {
- const MAX_ATTEMPTS = 5
- try {
- const supabase = await createAdminClient() || await createClient()
- const headersList = await headers()
- let ip = headersList.get("x-forwarded-for") || headersList.get("x-real-ip") || 'unknown'
- if (ip.includes(',')) ip = ip.split(',')[0].trim()
- if (ip === '::1') ip = '127.0.0.1'
-
- // Clean up old limits
- // Clean up old limits (logic simplified, variable unused)
-
- // Check current limit
- const { data: limit } = await supabase
- .from('rate_limits')
- .select('*')
- .eq('ip_address', ip)
- .eq('action', action)
- .single()
-
- if (!limit) {
- return { blocked: false, remaining: MAX_ATTEMPTS }
- }
-
- // If blocked
- if (limit.blocked_until && new Date(limit.blocked_until) > new Date()) {
- return { blocked: true, resetTime: new Date(limit.blocked_until) }
- }
-
- // If window expired, reset code handling happens in increment logic usually.
- // But here we just check.
- // Actually, simpler logic:
- // We will increment on failure. This function just checks if currently blocked.
-
- return { blocked: false, remaining: MAX_ATTEMPTS - (limit.count || 0) }
-
- } catch (error) {
- console.error('Rate limit check failed:', error)
- return { blocked: false } // Fail open
- }
-}
-
-export async function incrementRateLimit(action: string) {
- const BLOCK_DURATION_MINUTES = 15
-
- try {
- const supabase = await createAdminClient() || await createClient()
- const headersList = await headers()
- let ip = headersList.get("x-forwarded-for") || headersList.get("x-real-ip") || 'unknown'
- if (ip.includes(',')) ip = ip.split(',')[0].trim()
- if (ip === '::1') ip = '127.0.0.1'
-
- const { data: limit } = await supabase
- .from('rate_limits')
- .select('*')
- .eq('ip_address', ip)
- .eq('action', action)
- .single()
-
- if (limit) {
- // Check if we should reset (if last attempt was long ago)
- const lastAttempt = new Date(limit.last_attempt)
- const tenMinutesAgo = new Date(Date.now() - 10 * 60 * 1000)
-
- let newCount = limit.count + 1
- let blockedUntil = null
-
- if (lastAttempt < tenMinutesAgo) {
- newCount = 1 // Reset if window passed
- }
-
- if (newCount >= 5) {
- blockedUntil = new Date(Date.now() + BLOCK_DURATION_MINUTES * 60 * 1000).toISOString()
- }
-
- await supabase
- .from('rate_limits')
- .update({
- count: newCount,
- last_attempt: new Date().toISOString(),
- blocked_until: blockedUntil
- })
- .eq('id', limit.id)
- } else {
- await supabase.from('rate_limits').insert({
- ip_address: ip,
- action,
- count: 1,
- last_attempt: new Date().toISOString()
- })
- }
-
- } catch (error) {
- console.error('Rate limit increment failed:', error)
- }
-}
diff --git a/src/lib/supabase/session.ts b/src/lib/supabase/session.ts
index 3a4bc1b..f2f796d 100644
--- a/src/lib/supabase/session.ts
+++ b/src/lib/supabase/session.ts
@@ -36,22 +36,17 @@ export async function updateSession(request: NextRequest) {
if (
!user &&
!request.nextUrl.pathname.startsWith('/login') &&
- !request.nextUrl.pathname.startsWith('/auth')
+ !request.nextUrl.pathname.startsWith('/auth') &&
+ request.nextUrl.pathname !== '/' &&
+ !request.nextUrl.pathname.startsWith('/galeri')
) {
const url = request.nextUrl.clone()
url.pathname = '/login'
return NextResponse.redirect(url)
}
- // 2FA Enforcement
- if (user && !request.nextUrl.pathname.startsWith('/verify')) {
- const verifiedCookie = request.cookies.get('2fa_verified')
- if (!verifiedCookie) {
- const url = request.nextUrl.clone()
- url.pathname = '/verify'
- return NextResponse.redirect(url)
- }
- }
+ // 2FA Enforcement Removed
+
return supabaseResponse
}