125 lines
4.8 KiB
TypeScript
125 lines
4.8 KiB
TypeScript
"use server"
|
||
|
||
import { createClient } from "@/lib/supabase-server"
|
||
import { createClient as createSupabaseClient } from "@supabase/supabase-js"
|
||
|
||
import { cookies } from "next/headers"
|
||
import { NetGsmService } from "./netgsm"
|
||
// We will reuse sendTestSms logic or create a specific one. sendTestSms uses Netgsm Service.
|
||
// Better to export a generic 'sendSms' from lib/sms/actions.ts or just invoke the service directly.
|
||
// lib/sms/actions.ts has `sendBulkSms` and `sendTestSms`. I should probably expose a generic `sendSms` there.
|
||
|
||
// Admin client for Auth Codes table access
|
||
const supabaseAdmin = createSupabaseClient(
|
||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||
process.env.SUPABASE_SERVICE_ROLE_KEY!,
|
||
{ auth: { autoRefreshToken: false, persistSession: false } }
|
||
)
|
||
|
||
export async function sendVerificationCode() {
|
||
const supabase = createClient()
|
||
const { data: { user } } = await supabase.auth.getUser()
|
||
|
||
if (!user) return { error: "Kullanıcı bulunamadı." }
|
||
|
||
// 1. Get user phone
|
||
const { data: profile } = await supabaseAdmin
|
||
.from('profiles')
|
||
.select('phone')
|
||
.eq('id', user.id)
|
||
.single()
|
||
|
||
if (!profile?.phone) {
|
||
return { error: "Profilinizde telefon numarası tanımlı değil. Lütfen yöneticinizle iletişime geçin." }
|
||
}
|
||
|
||
// 2. Generate Code
|
||
const code = Math.floor(100000 + Math.random() * 900000).toString() // 6 digit
|
||
const expiresAt = new Date(Date.now() + 5 * 60 * 1000) // 5 mins
|
||
|
||
// 3. Store in DB
|
||
// First, delete old codes for this email/user
|
||
await supabaseAdmin.from('auth_codes').delete().eq('email', user.email!)
|
||
|
||
const { error: dbError } = await supabaseAdmin.from('auth_codes').insert({
|
||
email: user.email!,
|
||
code,
|
||
expires_at: expiresAt.toISOString()
|
||
})
|
||
|
||
if (dbError) {
|
||
console.error("Auth code db error:", dbError)
|
||
return { error: "Doğrulama kodu oluşturulamadı." }
|
||
}
|
||
|
||
// 4. Send SMS
|
||
// We import the logic from Netgsm service wrapper
|
||
// Since we don't have a direct 'sendSms' export in existing actions that accepts phone/message directly without admin assertion (which we have here via admin client, but the helper function `sendTestSms` does its own checks).
|
||
// I will use a direct call to the generic `NetgsmService` logic if I can, or modify `lib/sms/actions.ts` to export it.
|
||
// To avoid modifying too many files, I'll instantiate NetgsmService here if I can import it, or just use `sendBulkSms` with one number?
|
||
// `sendBulkSms` asserts admin user. But here the calling user IS logged in (but might not be admin?).
|
||
// Actually, `sendVerificationCode` is called by the logging-in user (who might be just 'user' role).
|
||
// `lib/sms/actions.ts` -> `assertAdmin()` checks if current user is admin.
|
||
// So if a normal user logs in, `sendBulkSms` will fail.
|
||
// WE NEED A SYSTEM LEVEL SEND FUNCTION.
|
||
|
||
// I will read credentials directly using Admin Client here.
|
||
const { data: settings } = await supabaseAdmin.from('sms_settings').select('*').single()
|
||
if (!settings) return { error: "SMS servisi yapılandırılmamış." }
|
||
|
||
// Import the class dynamically or duplicate usage?
|
||
// The class is in `./netgsm.ts` (based on actions.ts imports).
|
||
// Let's import { NetGsmService } from "./netgsm"
|
||
// NetGsmService imported at top
|
||
|
||
const mobileService = new NetGsmService({
|
||
username: settings.username,
|
||
password: settings.password,
|
||
header: settings.header,
|
||
apiUrl: settings.api_url
|
||
})
|
||
|
||
const smsResult = await mobileService.sendSms(profile.phone, `Giris Dogrulama Kodunuz: ${code}`)
|
||
|
||
if (!smsResult.success) {
|
||
console.error("SMS Send Error:", smsResult)
|
||
return { error: "SMS gönderilemedi. Lütfen daha sonra tekrar deneyin." }
|
||
}
|
||
|
||
return { success: true, phone: profile.phone.slice(-4) } // Return last 4 digits
|
||
}
|
||
|
||
export async function verifyCode(code: string) {
|
||
const supabase = createClient()
|
||
const { data: { user } } = await supabase.auth.getUser()
|
||
|
||
if (!user) return { error: "Oturum bulunamadı." }
|
||
|
||
// Check code
|
||
const { data: record, error } = await supabaseAdmin
|
||
.from('auth_codes')
|
||
.select('*')
|
||
.eq('email', user.email!)
|
||
.eq('code', code)
|
||
.gt('expires_at', new Date().toISOString())
|
||
.single()
|
||
|
||
if (error || !record) {
|
||
return { error: "Geçersiz veya süresi dolmuş kod." }
|
||
}
|
||
|
||
// Success: Set Cookie
|
||
cookies().set('parakasa_2fa_verified', 'true', {
|
||
httpOnly: true,
|
||
secure: process.env.NODE_ENV === 'production',
|
||
sameSite: 'lax',
|
||
path: '/',
|
||
maxAge: 60 * 60 * 24 // 24 hours
|
||
})
|
||
|
||
// Delete used code
|
||
await supabaseAdmin.from('auth_codes').delete().eq('id', record.id)
|
||
|
||
return { success: true }
|
||
}
|