banklink_lv 1.0.2 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,144 @@
1
+ module Banklink
2
+ module Seb
3
+ class Notification
4
+ include Banklink::Common
5
+
6
+ attr_accessor :params
7
+ attr_accessor :raw
8
+
9
+ # set this to an array in the subclass, to specify which IPs are allowed to send requests
10
+ attr_accessor :production_ips
11
+
12
+ def initialize(post, options = {})
13
+ @options = options
14
+ empty!
15
+ parse(post)
16
+ end
17
+
18
+ def gross_cents
19
+ (gross.to_f * 100.0).round
20
+ end
21
+
22
+ # This combines the gross and currency and returns a proper Money object.
23
+ # this requires the money library located at http://dist.leetsoft.com/api/money
24
+ def amount
25
+ return gross_cents
26
+ end
27
+
28
+ # reset the notification.
29
+ def empty!
30
+ @params = Hash.new
31
+ @raw = ""
32
+ end
33
+
34
+ # Check if the request comes from an official IP
35
+ def valid_sender?(ip)
36
+ return true if Rails.env == :test || production_ips.blank?
37
+ production_ips.include?(ip)
38
+ end
39
+
40
+ def complete?
41
+ params['IB_STATUS'] == 'ACCOMPLISHED'
42
+ end
43
+
44
+ def wait?
45
+ params['IB_SERVICE'] == '1201'
46
+ end
47
+
48
+ def failed?
49
+ params['IB_SERVICE'] == '1901'
50
+ end
51
+
52
+ def currency
53
+ params['IB_CURR']
54
+ end
55
+
56
+ def transaction_id
57
+ params['IB_PAYMENT_ID']
58
+ end
59
+
60
+ def sender_name
61
+ params['IB_PAYER_NAME']
62
+ end
63
+
64
+ def sender_bank_account
65
+ params['IB_PAYER_ACC']
66
+ end
67
+
68
+ def receiver_name
69
+ params['IB_REC_NAME']
70
+ end
71
+ alias_method :reciever_name, :receiver_name
72
+
73
+ def receiver_bank_account
74
+ params['IB_REC_ACC']
75
+ end
76
+ alias_method :reciever_bank_account, :receiver_bank_account
77
+
78
+ # When was this payment received by the client.
79
+ # We're expecting a dd.mm.yyyy format.
80
+ def received_at
81
+ require 'date'
82
+ date = params['IB_T_DATE']
83
+ return nil unless date
84
+ day, month, year = *date.split('.').map(&:to_i)
85
+ Date.civil(year, month, day)
86
+ end
87
+
88
+ def signature
89
+ Base64.decode64(params['IB_CRC'])
90
+ end
91
+
92
+ # The money amount we received, string.
93
+ def gross
94
+ params['IB_AMOUNT']
95
+ end
96
+
97
+ # Was this a test transaction?
98
+ def test?
99
+ params['IB_REC_ID'] == 'testvpos'
100
+ end
101
+
102
+ # TODO what should be here?
103
+ def status
104
+ complete? ? 'Completed' : 'Failed'
105
+ end
106
+
107
+ # If our request was sent automatically by the bank (true) or manually
108
+ # by the user triggering the callback by pressing a "return" button (false).
109
+ def automatic?
110
+ (params['IB_FROM_SERVER'].present? && params['IB_FROM_SERVER'].upcase == 'Y')
111
+ end
112
+
113
+ def success?
114
+ acknowledge && complete?
115
+ end
116
+
117
+ # We don't actually acknowledge the notification by making another request ourself,
118
+ # instead, we check the notification by checking the signature that came with the notification.
119
+ # This method has to be called when handling the notification & deciding whether to process the order.
120
+ # Example:
121
+ #
122
+ # def notify
123
+ # notify = Notification.new(params)
124
+ #
125
+ # if notify.acknowledge
126
+ # ... process order ... if notify.complete?
127
+ # else
128
+ # ... log possible hacking attempt ...
129
+ # end
130
+ def acknowledge
131
+ bank_signature_valid?(signature, params['IB_SERVICE'], params)
132
+ end
133
+
134
+ def get_data_string
135
+ generate_data_string(params['IB_SERVICE'], params, Seb.required_service_params)
136
+ end
137
+
138
+ def bank_signature_valid?(bank_signature, service_msg_number, sigparams)
139
+ Seb.get_bank_public_key.verify(OpenSSL::Digest::SHA1.new, bank_signature, generate_data_string(service_msg_number, sigparams, Seb.required_service_params))
140
+ end
141
+
142
+ end
143
+ end
144
+ end
@@ -1,27 +1,99 @@
1
- module Swedbank
2
-
3
- # Raw X509 certificate of the bank, string format.
4
- mattr_accessor :bank_certificate
5
- # RSA public key of the bank, taken from the X509 certificate of the bank. OpenSSL container.
6
- def self.get_bank_public_key
7
- cert = self.bank_certificate
8
- OpenSSL::X509::Certificate.new(cert.gsub(/ /, '')).public_key
9
- end
1
+ require 'banklink/swedbank/helper'
2
+ require 'banklink/swedbank/notification'
10
3
 
11
- mattr_accessor :private_key
12
- # Our RSA private key. OpenSSL container.
13
- def self.get_private_key
14
- private_key = self.private_key
15
- OpenSSL::PKey::RSA.new(private_key.gsub(/ /, ''))
16
- end
4
+ module Banklink
5
+ module Swedbank
17
6
 
18
- mattr_accessor :service_url
19
- def self.service_url
20
- self.service_url
21
- end
7
+ # Raw X509 certificate of the bank, string format.
8
+ mattr_accessor :bank_certificate
9
+ # RSA public key of the bank, taken from the X509 certificate of the bank. OpenSSL container.
10
+ def self.get_bank_public_key
11
+ cert = self.bank_certificate
12
+ OpenSSL::X509::Certificate.new(cert.gsub(/ /, '')).public_key
13
+ end
22
14
 
23
- def self.notification(post)
24
- Notification.new(post)
25
- end
15
+ mattr_accessor :private_key
16
+ # Our RSA private key. OpenSSL container.
17
+ def self.get_private_key
18
+ private_key = self.private_key
19
+ OpenSSL::PKey::RSA.new(private_key.gsub(/ /, ''))
20
+ end
21
+
22
+ mattr_accessor :service_url
26
23
 
24
+ def self.notification(post)
25
+ Notification.new(post)
26
+ end
27
+
28
+ def self.helper(order, account, options = {})
29
+ Helper.new(order, account, options)
30
+ end
31
+
32
+ # Define required fields for each service message.
33
+ # We need to know this in order to calculate VK_MAC
34
+ # from a given hash of parameters.
35
+ # Order of the parameters is important.
36
+ mattr_accessor :required_service_params
37
+ self.required_service_params = {
38
+ 1001 => [
39
+ 'VK_SERVICE',
40
+ 'VK_VERSION',
41
+ 'VK_SND_ID',
42
+ 'VK_STAMP',
43
+ 'VK_AMOUNT',
44
+ 'VK_CURR',
45
+ 'VK_ACC',
46
+ 'VK_NAME',
47
+ 'VK_REF',
48
+ 'VK_MSG'],
49
+ 1002 => [
50
+ 'VK_SERVICE',
51
+ 'VK_VERSION',
52
+ 'VK_SND_ID',
53
+ 'VK_STAMP',
54
+ 'VK_AMOUNT',
55
+ 'VK_CURR',
56
+ 'VK_REF',
57
+ 'VK_MSG' ],
58
+ 1101 => [
59
+ 'VK_SERVICE',
60
+ 'VK_VERSION',
61
+ 'VK_SND_ID',
62
+ 'VK_REC_ID',
63
+ 'VK_STAMP',
64
+ 'VK_T_NO',
65
+ 'VK_AMOUNT',
66
+ 'VK_CURR',
67
+ 'VK_REC_ACC',
68
+ 'VK_REC_NAME',
69
+ 'VK_SND_ACC',
70
+ 'VK_SND_NAME',
71
+ 'VK_REF',
72
+ 'VK_MSG',
73
+ 'VK_T_DATE'],
74
+ 1201 => [
75
+ 'VK_SERVICE',
76
+ 'VK_VERSION',
77
+ 'VK_SND_ID',
78
+ 'VK_REC_ID',
79
+ 'VK_STAMP',
80
+ 'VK_AMOUNT',
81
+ 'VK_CURR',
82
+ 'VK_REC_ACC',
83
+ 'VK_REC_NAME',
84
+ 'VK_SND_ACC',
85
+ 'VK_SND_NAME',
86
+ 'VK_REF',
87
+ 'VK_MSG'],
88
+ 1901 => [
89
+ 'VK_SERVICE',
90
+ 'VK_VERSION',
91
+ 'VK_SND_ID',
92
+ 'VK_REC_ID',
93
+ 'VK_STAMP',
94
+ 'VK_REF',
95
+ 'VK_MSG']
96
+ }
97
+
98
+ end
27
99
  end
@@ -0,0 +1,115 @@
1
+ module Banklink #:nodoc:
2
+ module Swedbank
3
+ class Helper
4
+ attr_reader :fields
5
+ include Banklink::Common
6
+
7
+ def initialize(order, account, options = {})
8
+
9
+ @options = options
10
+ @fields = {}
11
+
12
+ @options['VK_SND_ID'] = account
13
+ @options['VK_STAMP'] = order
14
+ @options['VK_AMOUNT'] = options[:amount]
15
+ @options['VK_CURR'] = options[:currency]
16
+ @options['VK_RETURN'] = options[:return]
17
+ @options['VK_REF'] = options[:reference] || ""
18
+ @options['VK_MSG'] = options[:message]
19
+ @options['VK_LANG'] = options[:lang] if options[:lang]
20
+
21
+ if options[:service_msg_number]
22
+ @service_msg_number = options.delete(:service_msg_number)
23
+ else
24
+ @service_msg_number = default_service_msg_number
25
+ end
26
+
27
+ add_required_params
28
+ add_vk_mac
29
+ add_charset_field
30
+ add_return_url_field
31
+ add_lang_field
32
+ end
33
+
34
+
35
+ def form_fields
36
+ @fields
37
+ end
38
+
39
+ def self.mapping(attribute, options = {})
40
+ self.mappings ||= {}
41
+ self.mappings[attribute] = options
42
+ end
43
+
44
+ def add_field(name, value)
45
+ return if name.blank? || value.blank?
46
+ @fields[name.to_s] = value.to_s
47
+ end
48
+
49
+ def add_vk_mac
50
+ # Signature used to validate previous parameters
51
+ add_field('VK_MAC', generate_mac(@service_msg_number, form_fields, Swedbank.required_service_params))
52
+ end
53
+
54
+ def add_return_url_field
55
+ add_field('VK_RETURN', @options['VK_RETURN'])
56
+ end
57
+
58
+ def add_lang_field
59
+ if @options['VK_LANG']
60
+ add_field(vk_lang_param, @options['VK_LANG'])
61
+ else
62
+ add_field vk_lang_param, vk_lang
63
+ end
64
+ end
65
+
66
+ def add_charset_field
67
+ add_field vk_charset_param, vk_charset
68
+ end
69
+
70
+ def add_required_params
71
+ required_params = Swedbank.required_service_params[@service_msg_number]
72
+ required_params.each do |param|
73
+ param_value = (@options.delete(param) || send(param.to_s.downcase)).to_s
74
+ add_field param, encode_to_utf8(param_value)
75
+ end
76
+ end
77
+
78
+ # Default parameters
79
+ def vk_charset
80
+ 'UTF-8'
81
+ end
82
+
83
+ def vk_charset_param
84
+ 'VK_ENCODING'
85
+ end
86
+
87
+ def vk_lang
88
+ 'LAT'
89
+ end
90
+
91
+ def vk_lang_param
92
+ 'VK_LANG'
93
+ end
94
+
95
+ def vk_service
96
+ @service_msg_number
97
+ end
98
+
99
+ def vk_version
100
+ '008'
101
+ end
102
+
103
+ def redirect_url
104
+ Swedbank.service_url
105
+ end
106
+
107
+ # Default service message number.
108
+ # Use '1002' because it requires the least amount of parameters.
109
+ def default_service_msg_number
110
+ 1002
111
+ end
112
+
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,156 @@
1
+ module Banklink
2
+ module Swedbank
3
+ class Notification
4
+ include Banklink::Common
5
+
6
+ attr_accessor :params
7
+ attr_accessor :raw
8
+
9
+ # set this to an array in the subclass, to specify which IPs are allowed to send requests
10
+ attr_accessor :production_ips
11
+
12
+ def initialize(post, options = {})
13
+ @options = options
14
+ empty!
15
+ parse(post)
16
+ end
17
+
18
+ def gross_cents
19
+ (gross.to_f * 100.0).round
20
+ end
21
+
22
+ # This combines the gross and currency and returns a proper Money object.
23
+ # this requires the money library located at http://dist.leetsoft.com/api/money
24
+ def amount
25
+ return gross_cents
26
+ end
27
+
28
+ # reset the notification.
29
+ def empty!
30
+ @params = Hash.new
31
+ @raw = ""
32
+ end
33
+
34
+ # Check if the request comes from an official IP
35
+ def valid_sender?(ip)
36
+ return true if Rails.env == :test || production_ips.blank?
37
+ production_ips.include?(ip)
38
+ end
39
+
40
+ # A helper method to parse the raw post of the request & return
41
+ # the right Notification subclass based on the sender id.
42
+ #def self.get_notification(http_raw_data)
43
+ # params = ActiveMerchant::Billing::Integrations::Notification.new(http_raw_data).params
44
+ # Banklink.get_class(params)::Notification.new(http_raw_data)
45
+ #end
46
+
47
+ def get_data_string
48
+ generate_data_string(params['VK_SERVICE'], params, Swedbank.required_service_params)
49
+ end
50
+
51
+ def bank_signature_valid?(bank_signature, service_msg_number, sigparams)
52
+ Swedbank.get_bank_public_key.verify(OpenSSL::Digest::SHA1.new, bank_signature, generate_data_string(service_msg_number, sigparams, Swedbank.required_service_params))
53
+ end
54
+
55
+ def complete?
56
+ params['VK_SERVICE'] == '1101'
57
+ end
58
+
59
+ def wait?
60
+ params['VK_SERVICE'] == '1201'
61
+ end
62
+
63
+ def failed?
64
+ params['VK_SERVICE'] == '1901'
65
+ end
66
+
67
+ def currency
68
+ params['VK_CURR']
69
+ end
70
+
71
+ # The order id we passed to the form helper.
72
+ def item_id
73
+ params['VK_STAMP']
74
+ end
75
+
76
+ def transaction_id
77
+ params['VK_REF']
78
+ end
79
+
80
+ def sender_name
81
+ params['VK_SND_NAME']
82
+ end
83
+
84
+ def sender_bank_account
85
+ params['VK_SND_ACC']
86
+ end
87
+
88
+ def receiver_name
89
+ params['VK_REC_NAME']
90
+ end
91
+ alias_method :reciever_name, :receiver_name
92
+
93
+ def receiver_bank_account
94
+ params['VK_REC_ACC']
95
+ end
96
+ alias_method :reciever_bank_account, :receiver_bank_account
97
+
98
+ # When was this payment received by the client.
99
+ # We're expecting a dd.mm.yyyy format.
100
+ def received_at
101
+ require 'date'
102
+ date = params['VK_T_DATE']
103
+ return nil unless date
104
+ day, month, year = *date.split('.').map(&:to_i)
105
+ Date.civil(year, month, day)
106
+ end
107
+
108
+ def signature
109
+ Base64.decode64(params['VK_MAC'])
110
+ end
111
+
112
+ # The money amount we received, string.
113
+ def gross
114
+ params['VK_AMOUNT']
115
+ end
116
+
117
+ # Was this a test transaction?
118
+ def test?
119
+ params['VK_REC_ID'] == 'testvpos'
120
+ end
121
+
122
+ # TODO what should be here?
123
+ def status
124
+ complete? ? 'Completed' : 'Failed'
125
+ end
126
+
127
+ # If our request was sent automatically by the bank (true) or manually
128
+ # by the user triggering the callback by pressing a "return" button (false).
129
+ def automatic?
130
+ params['VK_AUTO'].upcase == 'Y'
131
+ end
132
+
133
+ def success?
134
+ acknowledge && complete?
135
+ end
136
+
137
+ # We don't actually acknowledge the notification by making another request ourself,
138
+ # instead, we check the notification by checking the signature that came with the notification.
139
+ # This method has to be called when handling the notification & deciding whether to process the order.
140
+ # Example:
141
+ #
142
+ # def notify
143
+ # notify = Notification.new(params)
144
+ #
145
+ # if notify.acknowledge
146
+ # ... process order ... if notify.complete?
147
+ # else
148
+ # ... log possible hacking attempt ...
149
+ # end
150
+ def acknowledge
151
+ bank_signature_valid?(signature, params['VK_SERVICE'], params)
152
+ end
153
+
154
+ end
155
+ end
156
+ end