|
|
import crypto from 'crypto'; |
|
|
import { AppDataSource } from '../config/database'; |
|
|
import { ApiKey } from '../entities/ApiKey'; |
|
|
|
|
|
const apiKeyRepository = AppDataSource.getRepository(ApiKey); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function generateApiKey(): string { |
|
|
return `zurri_${crypto.randomBytes(32).toString('hex')}`; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function hashApiKey(key: string): Promise<string> { |
|
|
return crypto.createHash('sha256').update(key).digest('hex'); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function verifyApiKey( |
|
|
providedKey: string, |
|
|
userId: string |
|
|
): Promise<ApiKey | null> { |
|
|
const hashedKey = await hashApiKey(providedKey); |
|
|
|
|
|
const apiKey = await apiKeyRepository.findOne({ |
|
|
where: { |
|
|
key: hashedKey, |
|
|
userId, |
|
|
isActive: true, |
|
|
}, |
|
|
}); |
|
|
|
|
|
if (!apiKey) { |
|
|
return null; |
|
|
} |
|
|
|
|
|
|
|
|
if (apiKey.expiresAt && apiKey.expiresAt < new Date()) { |
|
|
return null; |
|
|
} |
|
|
|
|
|
|
|
|
apiKey.usageCount += 1; |
|
|
apiKey.lastUsedAt = new Date(); |
|
|
await apiKeyRepository.save(apiKey); |
|
|
|
|
|
return apiKey; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function createApiKey( |
|
|
userId: string, |
|
|
options?: { |
|
|
rateLimit?: number; |
|
|
expiresAt?: Date; |
|
|
} |
|
|
): Promise<{ key: string; apiKey: ApiKey }> { |
|
|
const rawKey = generateApiKey(); |
|
|
const hashedKey = await hashApiKey(rawKey); |
|
|
|
|
|
const apiKey = apiKeyRepository.create({ |
|
|
key: hashedKey, |
|
|
userId, |
|
|
rateLimit: options?.rateLimit, |
|
|
expiresAt: options?.expiresAt, |
|
|
isActive: true, |
|
|
}); |
|
|
|
|
|
const saved = await apiKeyRepository.save(apiKey); |
|
|
|
|
|
return { key: rawKey, apiKey: saved }; |
|
|
} |
|
|
|