← Назад к вопросам

Как обращаться к криптографическому сервису чтобы бизнес-логика знала как можно меньше о процессе шифрования?

1.0 Junior🔥 151 комментариев
#Soft Skills и рабочие процессы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Принцип Dependency Inversion и инкапсуляция

Для изоляции бизнес-логики от деталей криптографии нужно применить принцип инверсии зависимостей (Dependency Inversion Principle). Вместо того чтобы бизнес-логика знала о конкретной реализации шифрования, мы создаём абстрактный интерфейс криптографического сервиса.

Архитектурный подход

Вы должны определить интерфейс криптографического сервиса на уровне бизнес-логики (domain layer), а конкретная реализация будет находиться на уровне инфраструктуры.

// domain/services/CryptoService.interface.ts
export interface ICryptoService {
  encrypt(data: string): Promise<string>;
  decrypt(encryptedData: string): Promise<string>;
  hash(data: string): Promise<string>;
}

// application/usecases/UserRegistration.ts
export class RegisterUserUseCase {
  constructor(private cryptoService: ICryptoService) {}

  async execute(email: string, password: string): Promise<void> {
    // Бизнес-логика не знает ничего о том, как работает шифрование
    const hashedPassword = await this.cryptoService.hash(password);
    // ... сохраняем пользователя
  }
}

Конкретная реализация

Криптографический сервис реализуется на уровне инфраструктуры, полностью скрытый от бизнес-логики:

// infrastructure/services/CryptoServiceImpl.ts
import crypto from "crypto";
import { ICryptoService } from "@/domain/services/CryptoService.interface";

export class CryptoServiceImpl implements ICryptoService {
  private encryptionKey = process.env.ENCRYPTION_KEY!;

  async encrypt(data: string): Promise<string> {
    const iv = crypto.randomBytes(16);
    const cipher = crypto.createCipheriv(
      "aes-256-cbc",
      Buffer.from(this.encryptionKey),
      iv
    );
    let encrypted = cipher.update(data, "utf8", "hex");
    encrypted += cipher.final("hex");
    return iv.toString("hex") + ":" + encrypted;
  }

  async decrypt(encryptedData: string): Promise<string> {
    const [ivHex, encrypted] = encryptedData.split(":");
    const iv = Buffer.from(ivHex, "hex");
    const decipher = crypto.createDecipheriv(
      "aes-256-cbc",
      Buffer.from(this.encryptionKey),
      iv
    );
    let decrypted = decipher.update(encrypted, "hex", "utf8");
    decrypted += decipher.final("utf8");
    return decrypted;
  }

  async hash(data: string): Promise<string> {
    return crypto.createHash("sha256").update(data).digest("hex");
  }
}

Инъекция зависимостей

Когда вы создаёте бизнес-логику, вы передаёте реализацию через конструктор:

// presentation/controllers/AuthController.ts
export class AuthController {
  private registerUseCase: RegisterUserUseCase;

  constructor(cryptoService: ICryptoService) {
    this.registerUseCase = new RegisterUserUseCase(cryptoService);
  }

  async register(email: string, password: string) {
    await this.registerUseCase.execute(email, password);
  }
}

Тестирование

Использование интерфейса позволяет легко мокировать криптографический сервис в тестах:

// tests/usecases/UserRegistration.test.ts
const mockCryptoService: ICryptoService = {
  encrypt: jest.fn(),
  decrypt: jest.fn(),
  hash: jest.fn().mockResolvedValue("hashed-password")
};

const useCase = new RegisterUserUseCase(mockCryptoService);
await useCase.execute("user@example.com", "password");
expect(mockCryptoService.hash).toHaveBeenCalledWith("password");

Ключевые преимущества

  • Слабая связанность: бизнес-логика независима от реализации
  • Простота тестирования: можно использовать мок-объекты
  • Гибкость: легко заменить реализацию без изменения бизнес-логики
  • Читаемость: код в use case понятен и сосредоточен на логике