108 lines
2.2 KiB
TypeScript
108 lines
2.2 KiB
TypeScript
import bcrypt from 'bcryptjs'
|
|
import jwt from 'jsonwebtoken'
|
|
import { cookies } from 'next/headers'
|
|
import { prisma } from './prisma'
|
|
|
|
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production'
|
|
const SALT_ROUNDS = 10
|
|
|
|
export interface JWTPayload {
|
|
userId: string
|
|
email: string
|
|
role: string
|
|
}
|
|
|
|
export async function hashPassword(password: string): Promise<string> {
|
|
return bcrypt.hash(password, SALT_ROUNDS)
|
|
}
|
|
|
|
export async function verifyPassword(password: string, hash: string): Promise<boolean> {
|
|
return bcrypt.compare(password, hash)
|
|
}
|
|
|
|
export function generateToken(payload: JWTPayload): string {
|
|
return jwt.sign(payload, JWT_SECRET, { expiresIn: '7d' })
|
|
}
|
|
|
|
export function verifyToken(token: string): JWTPayload | null {
|
|
try {
|
|
return jwt.verify(token, JWT_SECRET) as JWTPayload
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export async function getCurrentUser() {
|
|
const cookieStore = await cookies()
|
|
const token = cookieStore.get('auth-token')?.value
|
|
|
|
if (!token) {
|
|
return null
|
|
}
|
|
|
|
const payload = verifyToken(token)
|
|
if (!payload) {
|
|
return null
|
|
}
|
|
|
|
const user = await prisma.user.findUnique({
|
|
where: { id: payload.userId },
|
|
select: {
|
|
id: true,
|
|
email: true,
|
|
username: true,
|
|
displayName: true,
|
|
avatarUrl: true,
|
|
bio: true,
|
|
role: true,
|
|
createdAt: true,
|
|
artist: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
slug: true,
|
|
verified: true,
|
|
},
|
|
},
|
|
label: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
slug: true,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
return user
|
|
}
|
|
|
|
export async function requireAuth() {
|
|
const user = await getCurrentUser()
|
|
if (!user) {
|
|
throw new Error('Unauthorized')
|
|
}
|
|
return user
|
|
}
|
|
|
|
export async function requireArtist() {
|
|
const user = await requireAuth()
|
|
if (!user.artist) {
|
|
throw new Error('Artist profile required')
|
|
}
|
|
return { user, artist: user.artist }
|
|
}
|
|
|
|
export function generateResetToken(): string {
|
|
return crypto.randomUUID()
|
|
}
|
|
|
|
export function slugify(text: string): string {
|
|
return text
|
|
.toLowerCase()
|
|
.replace(/[^\w\s-]/g, '')
|
|
.replace(/\s+/g, '-')
|
|
.replace(/-+/g, '-')
|
|
.trim()
|
|
}
|