feat: add modular services and repositories for improved code organization
Introduce repository pattern across multiple services, including `favorites`, `tags`, `sessions`, `reports`, `auth`, and more. Decouple crypto functionalities into modular services like `HashingService`, `JwtService`, and `EncryptionService`. Improve testability and maintainability by simplifying dependencies and consolidating utility logic.
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
import { createHash, randomBytes } from "node:crypto";
|
||||
import { randomBytes } from "node:crypto";
|
||||
import { Injectable, Logger } from "@nestjs/common";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { DatabaseService } from "../database/database.service";
|
||||
import { apiKeys } from "../database/schemas";
|
||||
import { HashingService } from "../crypto/services/hashing.service";
|
||||
import { ApiKeysRepository } from "./repositories/api-keys.repository";
|
||||
|
||||
@Injectable()
|
||||
export class ApiKeysService {
|
||||
private readonly logger = new Logger(ApiKeysService.name);
|
||||
|
||||
constructor(private readonly databaseService: DatabaseService) {}
|
||||
constructor(
|
||||
private readonly apiKeysRepository: ApiKeysRepository,
|
||||
private readonly hashingService: HashingService,
|
||||
) {}
|
||||
|
||||
async create(userId: string, name: string, expiresAt?: Date) {
|
||||
this.logger.log(`Creating API key for user ${userId}: ${name}`);
|
||||
@@ -16,9 +18,9 @@ export class ApiKeysService {
|
||||
const randomPart = randomBytes(24).toString("hex");
|
||||
const key = `${prefix}${randomPart}`;
|
||||
|
||||
const keyHash = createHash("sha256").update(key).digest("hex");
|
||||
const keyHash = await this.hashingService.hashSha256(key);
|
||||
|
||||
await this.databaseService.db.insert(apiKeys).values({
|
||||
await this.apiKeysRepository.create({
|
||||
userId,
|
||||
name,
|
||||
prefix: prefix.substring(0, 8),
|
||||
@@ -34,37 +36,18 @@ export class ApiKeysService {
|
||||
}
|
||||
|
||||
async findAll(userId: string) {
|
||||
return await this.databaseService.db
|
||||
.select({
|
||||
id: apiKeys.id,
|
||||
name: apiKeys.name,
|
||||
prefix: apiKeys.prefix,
|
||||
isActive: apiKeys.isActive,
|
||||
lastUsedAt: apiKeys.lastUsedAt,
|
||||
expiresAt: apiKeys.expiresAt,
|
||||
createdAt: apiKeys.createdAt,
|
||||
})
|
||||
.from(apiKeys)
|
||||
.where(eq(apiKeys.userId, userId));
|
||||
return await this.apiKeysRepository.findAll(userId);
|
||||
}
|
||||
|
||||
async revoke(userId: string, keyId: string) {
|
||||
this.logger.log(`Revoking API key ${keyId} for user ${userId}`);
|
||||
return await this.databaseService.db
|
||||
.update(apiKeys)
|
||||
.set({ isActive: false, updatedAt: new Date() })
|
||||
.where(and(eq(apiKeys.id, keyId), eq(apiKeys.userId, userId)))
|
||||
.returning();
|
||||
return await this.apiKeysRepository.revoke(userId, keyId);
|
||||
}
|
||||
|
||||
async validateKey(key: string) {
|
||||
const keyHash = createHash("sha256").update(key).digest("hex");
|
||||
const keyHash = await this.hashingService.hashSha256(key);
|
||||
|
||||
const [apiKey] = await this.databaseService.db
|
||||
.select()
|
||||
.from(apiKeys)
|
||||
.where(and(eq(apiKeys.keyHash, keyHash), eq(apiKeys.isActive, true)))
|
||||
.limit(1);
|
||||
const apiKey = await this.apiKeysRepository.findActiveByKeyHash(keyHash);
|
||||
|
||||
if (!apiKey) return null;
|
||||
|
||||
@@ -73,10 +56,7 @@ export class ApiKeysService {
|
||||
}
|
||||
|
||||
// Update last used at
|
||||
await this.databaseService.db
|
||||
.update(apiKeys)
|
||||
.set({ lastUsedAt: new Date() })
|
||||
.where(eq(apiKeys.id, apiKey.id));
|
||||
await this.apiKeysRepository.updateLastUsed(apiKey.id);
|
||||
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user