🔐 Безопасность • ⚡ Скорость • 🛡️ Защита от мошенничества • 🌍 Двуязычная документация
КазнаТок — это готовый к продакшену Ruby gem для интеграции с платёжным шлюзом Kaznatok (КазнаТок). Предоставляет безопасный, хорошо протестированный интерфейс для обработки онлайн-платежей с функциями корпоративной надёжности.
| Функция | Описание |
|---|---|
| 💳 Платёжные операции | Авторизация, подтверждение списания и возврат |
| 🔐 Подпись HMAC-SHA1 | Криптографическая аутентификация каждого запроса |
| 🔄 Умные повторы | Экспоненциальная задержка при временных сбоях |
| 🛡️ Circuit Breaker | Защита от каскадных отказов с автовосстановлением |
| 🔁 Защита от дублей | Thread-safe предотвращение повторных платежей |
| ✅ Верификация вебхуков | Constant-time проверка HMAC-подписи callback-уведомлений |
| 💚 Мониторинг | Проверка доступности шлюза без проведения платежа |
| 🔗 Middleware Pipeline | Расширяемая цепочка обработки запросов/ответов |
| ⏱️ ChronoShield | Многоуровневая система защиты от мошенничества |
| 🧵 Потокобезопасность | Все компоненты используют Mutex |
| 📦 Без зависимостей | Только стандартная библиотека Ruby (net/http, openssl, digest) |
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.
| 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 kaznatokAdd to your Gemfile:
gem 'kaznatok'Then run:
bundle installOr install directly:
gem install kaznatokrequire '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) ДОЛЖНЫ загружаться из переменных окружения. Никогда не храните их в коде!
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!
| Параметр | По умолчанию | Описание / 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 |
Блокирует средства на счёте держателя карты
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 при успехеПодтверждает списание средств после успешной авторизации
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)Отменяет ранее авторизованную или подтверждённую транзакцию
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)Click to expand English examples
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 successoptions = 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)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 "Не выполнится!" }
# => вернёт кешированный результат, блок НЕ выполнитсяТри состояния: закрыт → открыт → полуоткрыт
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Расширяемая цепочка обработки запросов/ответов
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)Многоуровневая система защиты от мошенничества
# Создание щита с пользовательскими параметрами
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
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 resultbreaker = 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"
endverifier = Kaznatok::WebhookVerifier.new
if verifier.verify(request.body, params['signature'])
process_payment_notification(params)
else
halt 403, 'Invalid signature'
endstatus = Kaznatok::HealthCheck.ping
# => { available: true, latency_ms: 142, status_code: 200 }pipeline = Kaznatok::Middleware::Pipeline.new
pipeline.use(Kaznatok::Middleware::LoggerMiddleware.new)
# Custom middleware...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}с")
endbegin
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")
endKaznatok::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
| Константа | Код | 🇷🇺 Описание | 🇬🇧 Description |
|---|---|---|---|
Kaznatok::TransactionType::AUTH |
0 |
Авторизация (блокировка средств) | Authorization (fund blocking) |
Kaznatok::TransactionType::CHECKOUT |
21 |
Подтверждение списания | Checkout (fund deduction) |
Kaznatok::TransactionType::REVERSAL |
24 |
Отмена / возврат | Reversal (cancellation/refund) |
| Модуль | Назначение / 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# Install dependencies
bundle install
# Run tests
rake test
# Run demo
ruby examples/demo.rbkaznatok/
├── 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.
This project is licensed under the MIT License. See LICENSE.txt for details.
Смотрите CHANGELOG.md для истории версий.
See CHANGELOG.md for version history.
Мы приветствуем ваш вклад! Ознакомьтесь с CONTRIBUTING.md и CODE_OF_CONDUCT.md.
Contributions are welcome! See CONTRIBUTING.md and CODE_OF_CONDUCT.md.
Сообщить об уязвимости: смотрите SECURITY.md.
Report a vulnerability: see SECURITY.md.
Kaznatok v3.0.0 — Безопасные платежи, просто.
Made with ❤️ for the Ruby community