Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce hash algorithms and make some refactoring #29

Merged
merged 5 commits into from
Mar 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ tmp
.DS_Store
passenger.3000.log
passenger.3000.pid.lock
.idea

# YARD artifacts
.yardoc
Expand Down
Empty file removed app/controllers/.gitkeep
Empty file.
18 changes: 8 additions & 10 deletions app/controllers/robokassa_controller.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
# -*- encoding : utf-8 -*-
class RobokassaController < ApplicationController

class RobokassaController < ActionController::Base
if respond_to?(:before_action)
before_action :create_notification
else
before_filter :create_notification
end

def paid
def result
if @notification.valid_result_signature?
instance_exec @notification, &Rubykassa.result_callback
else
Expand All @@ -29,11 +27,11 @@ def fail

private

def create_notification
if request.get?
@notification = Rubykassa::Notification.new request.query_parameters
elsif request.post?
@notification = Rubykassa::Notification.new request.request_parameters
end
def create_notification
if request.get?
@notification = Rubykassa::Notification.new request.query_parameters
elsif request.post?
@notification = Rubykassa::Notification.new request.request_parameters
end
end
end
10 changes: 6 additions & 4 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# -*- encoding : utf-8 -*-
Rails.application.routes.draw do
if Rubykassa::Client.configuration
scope '/robokassa' do
%w(paid success fail).map do |route|
method(Rubykassa.http_method).call "/#{route}" => "robokassa##{route}", as: "robokassa_#{route}"
scope :robokassa do
%w(result success fail).map do |route|
match route,
controller: :robokassa,
action: route,
via: Rubykassa.http_method
end
end
end
Expand Down
7 changes: 4 additions & 3 deletions lib/generators/rubykassa/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

module Rubykassa
class InstallGenerator < Rails::Generators::Base
source_root File.expand_path("../templates", __FILE__)
source_root File.expand_path('../templates', __FILE__)
def create_initializer_file
template 'rubykassa.rb', File.join('config', 'initializers', 'rubykassa.rb')
template 'rubykassa.rb',
File.join('config', 'initializers', 'rubykassa.rb')
end
end
end
end
14 changes: 8 additions & 6 deletions lib/generators/rubykassa/templates/rubykassa.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
# -*- encoding : utf-8 -*-
Rubykassa.configure do |config|
config.login = ENV["ROBOKASSA_LOGIN"]
config.first_password = ENV["ROBOKASSA_FIRST_PASSWORD"]
config.second_password = ENV["ROBOKASSA_SECOND_PASSWORD"]
config.login = ENV['ROBOKASSA_LOGIN']
config.first_password = ENV['ROBOKASSA_FIRST_PASSWORD']
config.second_password = ENV['ROBOKASSA_SECOND_PASSWORD']
config.mode = :test # or :production
config.http_method = :get # or :post
config.xml_http_method = :get # or :post
config.hash_algorithm = :md5 # or :ripemd160, :sha1, :sha256, :sha384, :sha512


# Result callback is called in RobokassaController#paid action if valid signature
# Result callback is called in RobokassaController#result action if valid signature
# was generated. It should always return "OK#{ invoice_id }" string, so implement
# your custom logic above `render text: notification.success` line

config.result_callback = ->(notification) { render text: notification.success }
config.result_callback = ->(notification) do
render text: notification.success
end

# Define success or failure callbacks here like:

Expand Down
1 change: 0 additions & 1 deletion lib/rubykassa.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- encoding : utf-8 -*-
require 'rubykassa/engine'
require 'rubykassa/client'
require 'rubykassa/payment_interface'
Expand Down
9 changes: 4 additions & 5 deletions lib/rubykassa/action_view_extension.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
# -*- encoding : utf-8 -*-
module Rubykassa
module ActionViewExtension
def pay_url(phrase, invoice_id, total, options = {}, &block)
total, invoice_id = total.to_s, invoice_id.to_s
extra_params = options.except([:custom, :html])
extra_params = options.except :custom, :html
custom_params = options[:custom] ||= {}
html_params = options[:html] ||= {}

url = Rubykassa.pay_url invoice_id, total, custom_params, extra_params
if block_given?
link_to(phrase, Rubykassa.pay_url(invoice_id, total, custom_params, extra_params), html_params, &block)
link_to phrase, url, html_params, &block
else
link_to(phrase, Rubykassa.pay_url(invoice_id, total, custom_params, extra_params), html_params)
link_to phrase, url, html_params
end
end
end
Expand Down
40 changes: 23 additions & 17 deletions lib/rubykassa/client.rb
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
# -*- encoding : utf-8 -*-
require 'rubykassa/configuration'

module Rubykassa
class ConfigurationError < StandardError
class << self
def raise_errors_for(configuration)
if !configuration.correct_mode?
raise ConfigurationError, "Ivalid mode: only :test or :production are allowed"
end
ENV_MESSAGE =
'Invalid mode: only :test or :production are allowed'.freeze
HTTP_METHOD_MESSAGE =
'Invalid http method: only :get or :post are allowed'.freeze
HASH_ALGORITHM_MESSAGE = <<-MESSAGE.squish.freeze
Invalid hash algorithm: only
#{Configuration::HASH_ALGORITHMS.map(&:upcase).join ', '} are allowed
MESSAGE

if !configuration.correct_http_method? || !configuration.correct_xml_http_method?
raise ConfigurationError, "Ivalid http method: only :get or :post are allowed"
end
def self.raise_errors_for(configuration)
if !configuration.correct_mode?
raise ConfigurationError, ENV_MESSAGE
end
if !configuration.correct_http_method? ||
!configuration.correct_xml_http_method?
raise ConfigurationError, HTTP_METHOD_MESSAGE
end
if !configuration.correct_hash_algorithm?
raise ConfigurationError, HASH_ALGORITHM_MESSAGE
end
end
end

class Client
class << self
attr_accessor :configuration

def configure
self.configuration = Rubykassa::Configuration.new
yield self.configuration
ConfigurationError.raise_errors_for(self.configuration)
end
cattr_accessor :configuration
def self.configure
self.configuration = Rubykassa::Configuration.new
yield self.configuration
ConfigurationError.raise_errors_for(self.configuration)
end
end
end
22 changes: 15 additions & 7 deletions lib/rubykassa/configuration.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
# -*- encoding : utf-8 -*-
module Rubykassa
class Configuration
ATTRIBUTES = [
:login, :first_password, :second_password, :mode, :http_method, :xml_http_method,
:success_callback, :fail_callback, :result_callback
:login, :first_password, :second_password, :mode, :http_method,
:xml_http_method, :success_callback, :fail_callback, :result_callback,
:hash_algorithm
]
HASH_ALGORITHMS = [:md5, :ripemd160, :sha1, :sha256, :sha384, :sha512]

attr_accessor *ATTRIBUTES

def initialize
self.login = "your_login"
self.first_password = "first_password"
self.second_password = "second_password"
self.login = 'your_login'
self.first_password = 'first_password'
self.second_password = 'second_password'
self.mode = :test
self.http_method = :get
self.xml_http_method = :get
self.hash_algorithm = :md5
self.success_callback = ->(notification) { render text: 'success' }
self.fail_callback = ->(notification) { render text: 'fail' }
self.result_callback = ->(notification) { render text: notification.success }
self.result_callback = ->(notification) do
render text: notification.success
end
end

def correct_mode?
Expand All @@ -31,5 +35,9 @@ def correct_http_method?
def correct_xml_http_method?
[:get, :post].include?(xml_http_method)
end

def correct_hash_algorithm?
HASH_ALGORITHMS.include?(hash_algorithm)
end
end
end
3 changes: 1 addition & 2 deletions lib/rubykassa/engine.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# -*- encoding : utf-8 -*-
require 'rubykassa/action_view_extension'

module Rubykassa
class Engine < ::Rails::Engine
initializer "rubykassa.action_view_extension" do
initializer 'rubykassa.action_view_extension' do
ActionView::Base.send :include, Rubykassa::ActionViewExtension
end
end
Expand Down
11 changes: 6 additions & 5 deletions lib/rubykassa/notification.rb
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
# -*- encoding : utf-8 -*-
require 'rubykassa/signature_generator'

module Rubykassa
class Notification
include SignatureGenerator

attr_accessor :params
attr_reader :invoice_id, :total

def initialize(params)
def initialize(params = {})
@params = HashWithIndifferentAccess.new(params)
@invoice_id = @params["InvId"]
@total = @params["OutSum"]
@invoice_id = @params['InvId']
@total = @params['OutSum']
end

%w(result success).map do |kind|
define_method "valid_#{kind}_signature?" do
@params["SignatureValue"].to_s.downcase == generate_signature_for(kind.to_sym)
@params['SignatureValue'].to_s.downcase ==
generate_signature_for(kind.to_sym)
end
end

Expand Down
46 changes: 25 additions & 21 deletions lib/rubykassa/payment_interface.rb
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
# -*- encoding : utf-8 -*-
require 'rubykassa/signature_generator'

module Rubykassa
class PaymentInterface
include SignatureGenerator

BASE_URL = "https://auth.robokassa.ru/Merchant/Index.aspx".freeze

BASE_URL = 'https://auth.robokassa.ru/Merchant/Index.aspx'.freeze
PARAMS_CONFORMITY = {
login: "MerchantLogin",
total: "OutSum",
invoice_id: "InvId",
signature: "SignatureValue",
email: "Email",
currency: "IncCurrLabel",
description: "Desc",
culture: "Culture",
is_test: "IsTest"
}
login: 'MerchantLogin'.freeze,
total: 'OutSum'.freeze,
invoice_id: 'InvId'.freeze,
signature: 'SignatureValue'.freeze,
email: 'Email'.freeze,
currency: 'IncCurrLabel'.freeze,
description: 'Desc'.freeze,
culture: 'Culture'.freeze,
is_test: 'IsTest'.freeze
}.freeze

attr_accessor :invoice_id, :total, :params

def initialize &block
def initialize(&block)
instance_eval &block if block_given?
shpfy_params
end
Expand All @@ -31,31 +29,37 @@ def test_mode?
end

def pay_url(extra_params = {})
extra_params = extra_params.slice(:currency, :description, :email, :culture)

"#{BASE_URL}?" + initial_options.merge(extra_params).map do |key, value|
extra_params = extra_params.slice :currency, :description, :email,
:culture
result_params = initial_options.merge(extra_params).map do |key, value|
if key =~ /^shp/
"#{key}=#{value}"
else
"#{PARAMS_CONFORMITY[key]}=#{value}"
end
end.compact.join("&")
end
BASE_URL.dup << '?' << result_params.compact.join('&')
end

def initial_options
{
result = {
login: Rubykassa.login,
total: @total,
invoice_id: @invoice_id,
is_test: test_mode? ? 1 : 0,
signature: generate_signature_for(:payment)
}.merge(Hash[@params.sort.map {|param_name| [param_name[0], param_name[1]]}])
}
custom_params = @params.sort.map { |param_name| param_name.first 2 }
result.merge Hash[custom_params]
end

private

def shpfy_params
@params = @params.map {|param_name| ["shp#{param_name[0]}".to_sym, param_name[1]]}
@params = @params.map do |param_name|
# REFACTOR: #to_sym on params-based strings will cause memory bloat on Ruby prior to 2.2
["shp#{param_name[0]}".to_sym, param_name[1]]
end
end
end
end
Loading