Skip to content

Otec999/kaznatok

Repository files navigation

💎 Kaznatok (КазнаТок) v3.0.0

🏦 Современный Ruby-клиент для платёжного шлюза КазнаТок


Gem Version Ruby License: MIT Tests

🔐 Безопасность • ⚡ Скорость • 🛡️ Защита от мошенничества • 🌍 Двуязычная документация


📋 Содержание

🇷🇺 Русский 🇬🇧 English
О проекте About
Установка Installation
Конфигурация Configuration
Использование Usage
Продвинутые функции Advanced Features
Обработка ошибок Error Handling
Справочник API API Reference
Разработка Development

🌟 О проекте

КазнаТок — это готовый к продакшену Ruby gem для интеграции с платёжным шлюзом Kaznatok (КазнаТок). Предоставляет безопасный, хорошо протестированный интерфейс для обработки онлайн-платежей с функциями корпоративной надёжности.

✨ Основные возможности

Функция Описание
💳 Платёжные операции Авторизация, подтверждение списания и возврат
🔐 Подпись HMAC-SHA1 Криптографическая аутентификация каждого запроса
🔄 Умные повторы Экспоненциальная задержка при временных сбоях
🛡️ Circuit Breaker Защита от каскадных отказов с автовосстановлением
🔁 Защита от дублей Thread-safe предотвращение повторных платежей
Верификация вебхуков Constant-time проверка HMAC-подписи callback-уведомлений
💚 Мониторинг Проверка доступности шлюза без проведения платежа
🔗 Middleware Pipeline Расширяемая цепочка обработки запросов/ответов
⏱️ ChronoShield Многоуровневая система защиты от мошенничества
🧵 Потокобезопасность Все компоненты используют Mutex
📦 Без зависимостей Только стандартная библиотека Ruby (net/http, openssl, digest)

🌟 About

Kaznatok is a production-ready Ruby gem for integrating with the Kaznatok (КазнаТок) electronic payment gateway. It provides a secure, well-tested interface for processing online payments with enterprise-grade reliability features.

✨ Key Features

Feature Description
💳 Payment Operations Authorization, Checkout, and Reversal transactions
🔐 HMAC-SHA1 Signing Cryptographic message authentication for every request
🔄 Smart Retry Exponential backoff retry logic for transient failures
🛡️ Circuit Breaker Cascading failure protection with auto-recovery
🔁 Idempotency Guard Thread-safe duplicate payment prevention
Webhook Verifier Constant-time HMAC signature verification
💚 Health Check Gateway availability monitoring without payments
🔗 Middleware Pipeline Extensible request/response processing chain
⏱️ ChronoShield Multi-layer fraud protection system
🧵 Thread-Safe All components use Mutex for concurrent safety
📦 Zero Dependencies Uses only Ruby stdlib (net/http, openssl, digest)

📦 Установка

Добавьте в ваш Gemfile:

gem 'kaznatok'

Затем выполните:

bundle install

Или установите напрямую:

gem install kaznatok

🇬🇧 Installation

Add to your Gemfile:

gem 'kaznatok'

Then run:

bundle install

Or install directly:

gem install kaznatok

⚙️ Конфигурация

require 'kaznatok'

Kaznatok.configure do |config|
  # Обязательные параметры — загружайте из переменных окружения!
  config.endpoint       = ENV['KAZNATOK_ENDPOINT']       # URL шлюза
  config.terminal       = ENV['KAZNATOK_TERMINAL']       # ID терминала
  config.secret_key     = ENV['KAZNATOK_SECRET_KEY']     # Секретный ключ (hex)

  # Информация о мерчанте
  config.merchant_name  = 'Мой Магазин'
  config.merchant_url   = 'https://myshop.example.com'
  config.merchant_email = 'payments@myshop.example.com'
  config.country_code   = 'RU'
  config.gmt_offset     = '+3'

  # Настройки надёжности
  config.retry_count    = 3        # Количество попыток повтора
  config.retry_delay    = 1.0      # Базовая задержка в секундах (экспоненциальная)
  config.timeout        = 30       # Таймаут HTTP в секундах
  config.ssl_verify     = true     # Проверка SSL-сертификата
end

⚠️ Предупреждение безопасности: Все чувствительные значения (endpoint, terminal, secret_key) ДОЛЖНЫ загружаться из переменных окружения. Никогда не храните их в коде!

🇬🇧 Configuration

require 'kaznatok'

Kaznatok.configure do |config|
  # Required — load from environment variables!
  config.endpoint       = ENV['KAZNATOK_ENDPOINT']       # Gateway URL
  config.terminal       = ENV['KAZNATOK_TERMINAL']       # Terminal ID
  config.secret_key     = ENV['KAZNATOK_SECRET_KEY']     # Hex-encoded secret key

  # Merchant information
  config.merchant_name  = 'My Shop'
  config.merchant_url   = 'https://myshop.example.com'
  config.merchant_email = 'payments@myshop.example.com'
  config.country_code   = 'RU'
  config.gmt_offset     = '+3'

  # Reliability settings
  config.retry_count    = 3        # Number of retry attempts
  config.retry_delay    = 1.0      # Base delay in seconds (exponential backoff)
  config.timeout        = 30       # HTTP timeout in seconds
  config.ssl_verify     = true     # SSL certificate verification
end

⚠️ Security Warning: All sensitive values (endpoint, terminal, secret_key) MUST be loaded from environment variables. Never hardcode them in source code!

📊 Параметры конфигурации / Configuration Parameters

Параметр По умолчанию Описание / Description
endpoint nil URL шлюза / Gateway URL
terminal nil ID терминала / Terminal ID
secret_key nil Секретный ключ (hex) / Hex-encoded secret key
merchant_name nil Название магазина / Merchant display name
merchant_url nil Сайт магазина / Merchant website URL
merchant_email nil Email магазина / Merchant contact email
country_code nil Код страны ISO / ISO country code
gmt_offset nil Смещение часового пояса / GMT timezone offset
user_agent "Kaznatok Ruby Gem 3.0.0" HTTP User-Agent header
retry_count 3 Макс. попыток / Max retry attempts
retry_delay 1.0 Базовая задержка (сек) / Base retry delay (seconds)
timeout 30 Таймаут HTTP (сек) / HTTP timeout (seconds)
ssl_verify true Проверка SSL / Verify SSL certificates
debug nil Режим отладки / Enable debug mode

🚀 Использование

💳 Авторизация (tr_type = 0)

Блокирует средства на счёте держателя карты

options = Kaznatok::Request.options_for_request(
  amount:   1500.50,
  currency: 'RUB',
  order:    'ORD-20260726-001',
  tr_type:  Kaznatok::TransactionType::AUTH,
  desc:     'Заказ #ORD-20260726-001',
  backref:  'https://myshop.example.com/callback'
)

result = Kaznatok::Request.process(options)
# => true при успехе

💰 Подтверждение списания (tr_type = 21)

Подтверждает списание средств после успешной авторизации

options = Kaznatok::Request.options_for_request(
  amount:   1500.50,
  currency: 'RUB',
  order:    'ORD-20260726-001',
  tr_type:  Kaznatok::TransactionType::CHECKOUT,
  rrn:      '123456789012',      # Retrieval Reference Number
  intref:   'ABCDEF123456'       # Internal Reference Number
)

result = Kaznatok::Request.process(options)

↩️ Возврат (tr_type = 24)

Отменяет ранее авторизованную или подтверждённую транзакцию

options = Kaznatok::Request.options_for_request(
  amount:   1500.50,
  currency: 'RUB',
  order:    'ORD-20260726-001',
  tr_type:  Kaznatok::TransactionType::REVERSAL,
  rrn:      '123456789012',
  intref:   'ABCDEF123456'
)

result = Kaznatok::Request.process(options)

🇬🇧 Usage

Click to expand English examples

💳 Authorization (tr_type = 0)

options = Kaznatok::Request.options_for_request(
  amount:   1500.50,
  currency: 'RUB',
  order:    'ORD-20260726-001',
  tr_type:  Kaznatok::TransactionType::AUTH,
  desc:     'Order #ORD-20260726-001',
  backref:  'https://myshop.example.com/callback'
)

result = Kaznatok::Request.process(options)
# => true on success

💰 Checkout (tr_type = 21)

options = Kaznatok::Request.options_for_request(
  amount:   1500.50,
  currency: 'RUB',
  order:    'ORD-20260726-001',
  tr_type:  Kaznatok::TransactionType::CHECKOUT,
  rrn:      '123456789012',
  intref:   'ABCDEF123456'
)

result = Kaznatok::Request.process(options)

↩️ Reversal (tr_type = 24)

options = Kaznatok::Request.options_for_request(
  amount:   1500.50,
  currency: 'RUB',
  order:    'ORD-20260726-001',
  tr_type:  Kaznatok::TransactionType::REVERSAL,
  rrn:      '123456789012',
  intref:   'ABCDEF123456'
)

result = Kaznatok::Request.process(options)

🛡️ Продвинутые функции

🔁 Защита от дублирования

Предотвращает повторные платежи для одного и того же ключа транзакции

guard = Kaznatok::IdempotencyGuard.new(ttl: 300) # 5 минут TTL

result = guard.execute('ORD-001', 1500.50, 'RUB', 0) do
  options = Kaznatok::Request.options_for_request(
    amount: 1500.50, currency: 'RUB', order: 'ORD-001',
    tr_type: Kaznatok::TransactionType::AUTH,
    desc: 'Заказ', backref: 'https://example.com/callback'
  )
  Kaznatok::Request.process(options)
end

# Второй вызов с тем же ключом вернёт кешированный результат
result2 = guard.execute('ORD-001', 1500.50, 'RUB', 0) { raise "Не выполнится!" }
# => вернёт кешированный результат, блок НЕ выполнится

🛡️ Circuit Breaker

Три состояния: закрыт → открыт → полуоткрыт

breaker = Kaznatok::CircuitBreaker.new(threshold: 5, cooldown: 60)

begin
  result = breaker.execute do
    Kaznatok::Request.process(options)
  end
rescue Kaznatok::CircuitBreaker::CircuitOpenError => e
  puts "⚠️ Шлюз недоступен. Повтор через #{e.retry_after.round(1)}с"
end

# Проверка статуса
puts breaker.status
# => { state: :closed, failure_count: 0, threshold: 5, cooldown: 60 }

✅ Верификация вебхуков

Проверяет HMAC-SHA1 подписи входящих callback-уведомлений

verifier = Kaznatok::WebhookVerifier.new

if verifier.verify(request.body, params['signature'])
  # ✅ Подпись верна — обрабатываем callback
  process_payment_notification(params)
else
  # ❌ Подпись не совпадает — отклоняем!
  halt 403, 'Неверная подпись'
end

💚 Мониторинг доступности

Проверяет доступность шлюза без проведения платежа

status = Kaznatok::HealthCheck.ping

puts status
# => { available: true, latency_ms: 142, status_code: 200 }

if status[:available]
  puts "✅ Шлюз доступен (#{status[:latency_ms]}мс)"
else
  puts "❌ Шлюз недоступен: #{status[:error]}"
end

🔗 Цепочка Middleware

Расширяемая цепочка обработки запросов/ответов

pipeline = Kaznatok::Middleware::Pipeline.new
pipeline.use(Kaznatok::Middleware::LoggerMiddleware.new)

# Пример пользовательского middleware
class MetricsMiddleware < Kaznatok::Middleware::Base
  def before_request(body)
    @start_time = Time.now
    body
  end

  def after_response(response)
    elapsed = Time.now - @start_time
    Statsd.timing('kaznatok.request', elapsed * 1000)
    response
  end
end

pipeline.use(MetricsMiddleware.new)

body = pipeline.run_before_request(request_body)
response = pipeline.run_after_response(raw_response)

⏱️ ChronoShield — Защита от мошенничества

Многоуровневая система защиты от мошенничества

# Создание щита с пользовательскими параметрами
shield = Kaznatok::ChronoShield.create(
  time_window: 300,        # Окно защиты от повторов в секундах
  max_per_minute: 10,      # Лимит запросов в минуту
  max_amount: 1_000_000    # Максимальная сумма одной транзакции
)

# 🔑 Temporal Fingerprint — уникальный идентификатор транзакции
fp = Kaznatok::ChronoShield.fingerprint
valid = Kaznatok::ChronoShield.valid_fingerprint?(fp)

# 🔒 Time Lock — защита от replay-атак
allowed = shield[:time_lock].allowed?('ORD-001')
# => true (первый вызов), false (повтор в пределах окна)

# 🔍 Anomaly Detector — обнаружение подозрительных паттернов
check = shield[:anomaly_detector].check(1500.50, 'ORD-001')
# => { safe: true, reasons: [] }

check = shield[:anomaly_detector].check(5_000_000, 'ORD-SUSPECT')
# => { safe: false, reasons: ["Сумма 5000000.0 превышает максимум 1000000"] }
🇬🇧 English examples

🔁 Idempotency Guard

guard = Kaznatok::IdempotencyGuard.new(ttl: 300) # 5 minutes TTL

result = guard.execute('ORD-001', 1500.50, 'RUB', 0) do
  options = Kaznatok::Request.options_for_request(
    amount: 1500.50, currency: 'RUB', order: 'ORD-001',
    tr_type: Kaznatok::TransactionType::AUTH,
    desc: 'Order', backref: 'https://example.com/callback'
  )
  Kaznatok::Request.process(options)
end
# Second call with same key returns cached result

🛡️ Circuit Breaker

breaker = Kaznatok::CircuitBreaker.new(threshold: 5, cooldown: 60)

begin
  result = breaker.execute { Kaznatok::Request.process(options) }
rescue Kaznatok::CircuitBreaker::CircuitOpenError => e
  puts "⚠️ Gateway unavailable. Retry after #{e.retry_after.round(1)}s"
end

✅ Webhook Verifier

verifier = Kaznatok::WebhookVerifier.new
if verifier.verify(request.body, params['signature'])
  process_payment_notification(params)
else
  halt 403, 'Invalid signature'
end

💚 Health Check

status = Kaznatok::HealthCheck.ping
# => { available: true, latency_ms: 142, status_code: 200 }

🔗 Middleware Pipeline

pipeline = Kaznatok::Middleware::Pipeline.new
pipeline.use(Kaznatok::Middleware::LoggerMiddleware.new)
# Custom middleware...

⏱️ ChronoShield

shield = Kaznatok::ChronoShield.create(
  time_window: 300,
  max_per_minute: 10,
  max_amount: 1_000_000
)
fp = Kaznatok::ChronoShield.fingerprint
allowed = shield[:time_lock].allowed?('ORD-001')
check = shield[:anomaly_detector].check(1500.50, 'ORD-001')

⚠️ Обработка ошибок

begin
  result = Kaznatok::Request.process(options)
rescue Kaznatok::ValidationError => e
  # Неверные параметры (нет полей, неправильный tr_type)
  logger.error("Ошибка валидации: #{e.message}")
  logger.error("Детали: #{e.errors.inspect}")

rescue Kaznatok::HTTPResponseError => e
  # Сетевая ошибка или HTTP-статус не 200
  logger.error("HTTP ошибка: #{e.message} (статус: #{e.response})")

rescue Kaznatok::GatewayResponseError => e
  # Шлюз вернул код ошибки в теле ответа
  logger.error("Ошибка шлюза: #{e.error_code}#{e.message}")
  logger.error("Сырой ответ: #{e.raw_response}")

rescue Kaznatok::CircuitBreaker::CircuitOpenError => e
  # Circuit breaker открыт — шлюз недоступен
  logger.warn("Circuit открыт. Повтор через #{e.retry_after}с")
end

🇬🇧 Error Handling

begin
  result = Kaznatok::Request.process(options)
rescue Kaznatok::ValidationError => e
  logger.error("Validation failed: #{e.message}")
rescue Kaznatok::HTTPResponseError => e
  logger.error("HTTP error: #{e.message} (status: #{e.response})")
rescue Kaznatok::GatewayResponseError => e
  logger.error("Gateway error: #{e.error_code}#{e.message}")
rescue Kaznatok::CircuitBreaker::CircuitOpenError => e
  logger.warn("Circuit open. Retry after #{e.retry_after}s")
end

📊 Иерархия ошибок / Error Hierarchy

Kaznatok::Error (базовый класс / base class)
├── Kaznatok::ValidationError          # Неверные параметры запроса / Invalid request parameters
├── Kaznatok::HTTPResponseError         # Сетевые/HTTP ошибки / Network/HTTP failures
├── Kaznatok::GatewayResponseError      # Коды ошибок шлюза / Gateway error codes
└── Kaznatok::CircuitBreaker::CircuitOpenError  # Circuit breaker открыт / Circuit breaker open

📖 Справочник API

Типы транзакций / Transaction Types

Константа Код 🇷🇺 Описание 🇬🇧 Description
Kaznatok::TransactionType::AUTH 0 Авторизация (блокировка средств) Authorization (fund blocking)
Kaznatok::TransactionType::CHECKOUT 21 Подтверждение списания Checkout (fund deduction)
Kaznatok::TransactionType::REVERSAL 24 Отмена / возврат Reversal (cancellation/refund)

Основные модули / Core Modules

Модуль Назначение / Purpose
Kaznatok::Request Формирование, подписание и отправка / Build, sign, and send requests
Kaznatok::RequestOptions Неизменяемые параметры запроса / Immutable request parameters
Kaznatok::Configuration DSL-конфигурация / DSL configuration
Kaznatok::TransactionType Константы типов транзакций / Transaction type constants
Kaznatok::IdempotencyGuard Защита от дублей / Duplicate payment prevention
Kaznatok::CircuitBreaker Защита от каскадных отказов / Cascading failure protection
Kaznatok::WebhookVerifier Проверка HMAC вебхуков / HMAC webhook verification
Kaznatok::HealthCheck Мониторинг шлюза / Gateway monitoring
Kaznatok::Middleware::Pipeline Цепочка обработки / Request/response chain
Kaznatok::Middleware::LoggerMiddleware Логирование с маскированием / Logging with secret masking
Kaznatok::ChronoShield Фасад защиты от мошенничества / Fraud protection facade
Kaznatok::ChronoShield::TemporalFingerprint Временные идентификаторы / Temporal identifiers
Kaznatok::ChronoShield::TimeLock Защита от повторов / Replay prevention
Kaznatok::ChronoShield::AnomalyDetector Детектор аномалий / Anomaly detection

🔧 Разработка

# Установка зависимостей
bundle install

# Запуск тестов
rake test

# Запуск демо
ruby examples/demo.rb

🇬🇧 Development

# Install dependencies
bundle install

# Run tests
rake test

# Run demo
ruby examples/demo.rb

📁 Структура проекта / Project Structure

kaznatok/
├── lib/
│   ├── kaznatok.rb                    # Точка входа / Entry point
│   └── kaznatok/
│       ├── version.rb                 # Версия / Version
│       ├── error.rb                   # Классы ошибок / Error classes
│       ├── configuration.rb           # Конфигурация / Config DSL
│       ├── transaction_type.rb        # Типы транзакций / Transaction types
│       ├── request_options.rb         # Параметры запроса / Request value object
│       ├── request.rb                 # HTTP-клиент / HTTP client
│       ├── idempotency_guard.rb       # Кеш дедупликации / Dedup cache
│       ├── circuit_breaker.rb         # Circuit breaker / Автомат выключения
│       ├── webhook_verifier.rb        # Верификатор HMAC / HMAC verifier
│       ├── health_check.rb            # Монитор здоровья / Health monitor
│       ├── middleware.rb              # Цепочка middleware / Middleware pipeline
│       ├── chrono_shield.rb           # Защита от мошенничества / Fraud protection
│       └── chrono_shield/
│           ├── temporal_fingerprint.rb # Временные метки / Temporal IDs
│           ├── time_lock.rb            # Блокировка повторов / Replay lock
│           └── anomaly_detector.rb     # Детектор аномалий / Anomaly detector
├── test/                              # Тесты / Test suite
├── examples/                          # Примеры / Demo scripts
├── kaznatok.gemspec                   # Спецификация гема / Gem specification
├── Gemfile                            # Зависимости / Dependencies
├── Rakefile                           # Задачи сборки / Build tasks
├── CHANGELOG.md                       # История версий / Version history
├── LICENSE.txt                        # Лицензия MIT / MIT License
├── CONTRIBUTING.md                    # Правила участия / Contribution guidelines
├── SECURITY.md                        # Политика безопасности / Security policy
└── CODE_OF_CONDUCT.md                 # Кодекс поведения / Code of conduct

📄 Лицензия

Этот проект распространяется под лицензией MIT. Подробности в LICENSE.txt.

🇬🇧 License

This project is licensed under the MIT License. See LICENSE.txt for details.


📝 История изменений

Смотрите CHANGELOG.md для истории версий.

🇬🇧 Changelog

See CHANGELOG.md for version history.


🤝 Участие в разработке

Мы приветствуем ваш вклад! Ознакомьтесь с CONTRIBUTING.md и CODE_OF_CONDUCT.md.

🇬🇧 Contributing

Contributions are welcome! See CONTRIBUTING.md and CODE_OF_CONDUCT.md.


🔒 Безопасность

Сообщить об уязвимости: смотрите SECURITY.md.

🇬🇧 Security

Report a vulnerability: see SECURITY.md.


💎 Сделано с ❤️ для Ruby-сообщества

Kaznatok v3.0.0 — Безопасные платежи, просто.

Made with ❤️ for the Ruby community

⬆ Наверх / Back to top

About

Ruby-клиент для платёжного шлюза КазнаТок (Kaznatok). Secure payment processing with HMAC-SHA1, Circuit Breaker, Idempotency Guard, Webhook Verification, and ChronoShield fraud protection. Zero dependencies — Ruby stdlib only.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages