Files
webshop/shop/lib/actions/auth.ts
DanielS 8f447d52e5
All checks were successful
Staging Build / build (push) Successful in 3m34s
Add lockout logic and email notification utils
2026-06-30 22:28:30 +02:00

148 lines
4.4 KiB
TypeScript

'use server'
import { createClient } from '@/lib/supabase/server'
import { createAdminClient } from '@/lib/supabase/admin'
import { headers } from 'next/headers'
import { sendLockoutEmail } from '@/lib/utils/email'
export async function signIn(email: string, password: string) {
try {
const supabase = await createClient()
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
})
if (error) {
// Track failed attempts
const { data: usr, error: usrError } = await supabase
.from('users')
.select('failed_attempts, email')
.eq('email', email)
.single()
const attempts = (usr?.failed_attempts ?? 0) + 1
// Update attempts count
await supabase
.from('users')
.update({ failed_attempts: attempts })
.eq('email', email)
// Lock account on 5th failure
if (attempts >= 5) {
await supabase
.from('users')
.update({ role: 'gesperrt' })
.eq('email', email)
// Notify admin
await sendLockoutEmail('info@hephex.de')
return { success: false, error: 'Konto gesperrt nach 5 Fehlversuchen.' }
}
return { success: false, error: error.message }
}
const userId = data.user?.id
if (userId) {
let { data: userData, error: userError } = await supabase
.from('users')
.select('role')
.eq('id', userId)
.single()
if (userError || !userData) {
// Fallback: create database records if missing for this authenticated user
try {
const adminSupabase = createAdminClient()
// Ensure profile exists
await adminSupabase.from('profiles').insert([{ id: userId }]).select()
// Ensure user exists
const { data: insertedUser, error: insertError } = await adminSupabase
.from('users')
.insert([{ id: userId, role: 'partner' }])
.select('role')
.single()
if (!insertError && insertedUser) {
userData = insertedUser
userError = null
}
} catch (adminErr) {
console.error("Failed to backfill user records:", adminErr)
}
}
if (userError || !userData || (userData.role !== 'partner' && userData.role !== 'admin')) {
await supabase.auth.signOut()
if (userData?.role === 'gesperrt') {
return { success: false, error: "Ihr Konto wurde gesperrt. Bitte wenden Sie sich an den Administrator." }
}
return { success: false, error: "Zugriff verweigert. Nur registrierte Partner dürfen sich anmelden." }
}
// Andere aktive Sitzungen beenden
await supabase.auth.signOut({ scope: 'others' })
return { success: true, role: userData.role }
}
return { success: true, role: 'partner' }
} catch (err: any) {
console.error("SignIn error:", err)
return { success: false, error: err?.message || "Ein unerwarteter Fehler ist aufgetreten." }
}
}
export async function signUp(email: string, password: string) {
throw new Error("Registrierung ist deaktiviert.")
}
export async function signOut() {
const supabase = await createClient()
const { error } = await supabase.auth.signOut()
if (error) {
throw new Error(error.message)
}
return { success: true }
}
export async function resetPassword(email: string) {
const supabase = await createClient()
const origin = (await headers()).get('origin') || ''
const { error } = await supabase.auth.resetPasswordForEmail(email, {
redirectTo: `${origin}/auth/update-password`,
})
if (error) {
throw new Error(error.message)
}
return { success: true }
}
export async function updatePassword(password: string) {
const supabase = await createClient()
const { error } = await supabase.auth.updateUser({ password })
if (error) {
throw new Error(error.message)
}
return { success: true }
}
export async function verifyAdmin() {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) throw new Error("Nicht authentifiziert.")
const { data: userData, error } = await supabase
.from('users')
.select('role')
.eq('id', user.id)
.single()
if (error || !userData || userData.role !== 'admin') {
throw new Error("Zugriff verweigert. Nur Administratoren erlaubt.")
}
return user
}