payhyper 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +6 -14
- data/lib/payhyper/version.rb +1 -1
- data/lib/payhyper.rb +67 -39
- data/payhyper.gemspec +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
ZTc5ZjgzZDc3Y2IxZWI1N2I1MzAyOTczYjg3ZWYwYjAzYjE1MDY0NjliYzkw
|
10
|
-
N2VjYWRmZWU5NDc0YWVjMTk1MzNjNDhmZDI0YWFkNjljYmMyYmNmOGI3ZDc5
|
11
|
-
YjQxNTdmMTZlOTA1YTkyYWFkM2Q4NDUwN2U1MTQxMmM2MGUwZjQ=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
NzJkYmRhMTZmODBmMzY5YjlmZDY0YWE5Mjk5Y2FlNGQxNmExODBjZDQxOTE1
|
14
|
-
NmE0YjMzYTY3MTllMWIzYjhlY2I5NTRlNGFhYTEzNDhiMGM1ZWQwMWM5Yzlh
|
15
|
-
MWIzNzk4N2Y3NGUxZThjOWFiY2E5ZjcxODIwN2FjODkzNzg0YWU=
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a0765918e4ad00fc1a1efb9c21030831110d50fe
|
4
|
+
data.tar.gz: 5f424f23813782dc5cdc916bd1c7ad03dbc09574
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 69080fb75e1f6cfb4eaa815100524d14f2c40c64bff2fc0eec990e1c92126119921259793f3d3b029a280e603f787d5f7cd8f6e146fea156afba1cb7481d3a4a
|
7
|
+
data.tar.gz: ee023675b08c6964f5d7644d5bc17516f67dde123760c98d80c9b981c10957c5c80e830399a9d265d94bf0ffcc55e6ad68e804c5f66a8bf804583bf21e97d171
|
data/lib/payhyper/version.rb
CHANGED
data/lib/payhyper.rb
CHANGED
@@ -35,14 +35,32 @@ module PayHyper
|
|
35
35
|
@base_url = BASE_URLS[mode]
|
36
36
|
end
|
37
37
|
|
38
|
-
def self.
|
39
|
-
|
38
|
+
def self.at_door!(name, phone, email, country, amount, currency, address = nil, invoice = nil, tag = nil) # TODO: There is a lot of overlap with "in_store!", refactor.
|
39
|
+
raise_if_not_setup!
|
40
|
+
# == Clean-up fields ==
|
41
|
+
currency = currency.upcase if currency && currency.is_a?(String)
|
42
|
+
country = country.upcase if country && country.is_a?(String)
|
43
|
+
if phone && phone.is_a?(String)
|
44
|
+
phone = phone.gsub(/[^0-9]/, "") # Remove non-numeric characters.
|
45
|
+
phone = phone.gsub(/^0*/, "") # Remove leading zeros.
|
46
|
+
if country && COUNTRY_CODES[country] && !phone.start_with?(COUNTRY_CODES[country])
|
47
|
+
phone = COUNTRY_CODES[country] + phone # Add country code.
|
48
|
+
end
|
49
|
+
end
|
50
|
+
# == Validate ==
|
51
|
+
raise ValidationError, "Country specified is incorrect or not supported." unless COUNTRIES.include?(country)
|
52
|
+
raise ValidationError, "Incorrect amount, must be positive." if amount.to_i <= 0
|
53
|
+
raise ValidationError, "Currency is incorrect or not supported." unless CURRENCIES.include?(currency)
|
54
|
+
raise ValidationError, "Incorrect phone, or not in a supported country." if phone.nil? || !phone.match(/\A962[0-9]{8,9}\z/)
|
55
|
+
raise ValidationError, "Invalid email." if email.nil? || !email.match(/\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/)
|
56
|
+
raise ValidationError, "Name is mandatory." if name.nil? || name.strip.length == 0
|
57
|
+
# == Do the request ==
|
58
|
+
make_call("/v1/at-door", { :name => name, :phone => phone, :email => email, :country => country, :amount => amount, :currency => currency, :address => address, :invoice => invoice, :tag => tag })
|
40
59
|
end
|
41
60
|
|
42
|
-
def self.
|
61
|
+
def self.in_store!(name, phone, email, country, amount, currency, tag = nil) # TODO: There is a lot of overlap with "at_door!", refactor.
|
43
62
|
raise_if_not_setup!
|
44
63
|
# == Clean-up fields ==
|
45
|
-
service = service.to_s.gsub("_", "-") if [:at_door, :in_store].include?(service)
|
46
64
|
currency = currency.upcase if currency && currency.is_a?(String)
|
47
65
|
country = country.upcase if country && country.is_a?(String)
|
48
66
|
if phone && phone.is_a?(String)
|
@@ -53,20 +71,61 @@ module PayHyper
|
|
53
71
|
end
|
54
72
|
end
|
55
73
|
# == Validate ==
|
56
|
-
raise ValidationError, "Incorrect service specified." unless ["at-door", "in-store"].include?(service)
|
57
74
|
raise ValidationError, "Country specified is incorrect or not supported." unless COUNTRIES.include?(country)
|
58
75
|
raise ValidationError, "Incorrect amount, must be positive." if amount.to_i <= 0
|
59
76
|
raise ValidationError, "Currency is incorrect or not supported." unless CURRENCIES.include?(currency)
|
60
77
|
raise ValidationError, "Incorrect phone, or not in a supported country." if phone.nil? || !phone.match(/\A962[0-9]{8,9}\z/)
|
61
78
|
raise ValidationError, "Invalid email." if email.nil? || !email.match(/\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/)
|
79
|
+
raise ValidationError, "Name is mandatory." if name.nil? || name.strip.length == 0
|
62
80
|
# == Do the request ==
|
63
|
-
|
81
|
+
make_call("/v1/in-store", { :name => name, :phone => phone, :email => email, :country => country, :amount => amount, :currency => currency, :tag => tag })
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.parse_notification(request)
|
85
|
+
raise_if_not_setup!
|
86
|
+
if check_ani_authenticity(request)
|
87
|
+
request.env["rack.input"].rewind # In case someone forgot to rewind the input.
|
88
|
+
body = request.env["rack.input"].read
|
89
|
+
request.env["rack.input"].rewind # Be nice to others.
|
90
|
+
JSON.load(body)
|
91
|
+
else
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class PayHyperError < StandardError; end
|
97
|
+
class ValidationError < PayHyperError; end
|
98
|
+
class CommunicationError < PayHyperError; end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def self.raise_if_not_setup!
|
103
|
+
raise PayHyperError, "Must call setup() first" if @access_key_id.nil? || @access_key_secret.nil? || @base_url.nil?
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.check_ani_authenticity(request)
|
107
|
+
authorization = request.env["HTTP_AUTHORIZATION"]
|
108
|
+
return false unless authorization
|
109
|
+
matches = authorization.match(/\A(.*) (.*):(.*)/)
|
110
|
+
return false unless matches
|
111
|
+
method, access_key_id, input_signature = matches.captures
|
112
|
+
return false unless method == "Hyper" && access_key_id && input_signature && access_key_id == @access_key_id
|
113
|
+
request.env["rack.input"].rewind # In case someone forgot to rewind the input.
|
114
|
+
body = request.env["rack.input"].read
|
115
|
+
request.env["rack.input"].rewind # Be nice to others.
|
116
|
+
canonical_request_representation = [request.env["REQUEST_METHOD"], request.env["HTTP_HOST"], request.env["PATH_INFO"], request.env["CONTENT_TYPE"], body].join("\n") # TODO: security bug if the webserver doesn't check host headers.
|
117
|
+
correct_signature = Security.sign(@access_key_secret, canonical_request_representation)
|
118
|
+
return Security.secure_compare(correct_signature, input_signature)
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.make_call(endpoint, body)
|
122
|
+
body = JSON.dump(body)
|
64
123
|
failure = "Unknown error"
|
65
124
|
begin
|
66
|
-
uri = URI.parse(@base_url +
|
125
|
+
uri = URI.parse(@base_url + endpoint)
|
67
126
|
content_type = "application/json; charset=utf-8"
|
68
127
|
signature = Security.sign(@access_key_secret, ["POST", uri.port == uri.default_port ? uri.host : "#{uri.host}:#{uri.port}", uri.request_uri, content_type, body.encode("UTF-8")].join("\n")) # Would be great if this could read directly from the request's headers.
|
69
|
-
res = RestClient.post(@base_url +
|
128
|
+
res = RestClient.post(@base_url + endpoint, body, :content_type => content_type, :authorization => "Hyper #{@access_key_id}:#{signature}")
|
70
129
|
failure = false
|
71
130
|
rescue RestClient::Exception => e # HTTP status codes not in 200-207, 301-303 and 307 result in a RestClient::Exception.
|
72
131
|
if e.http_code && e.http_code.to_i == 422 && e.http_body
|
@@ -96,35 +155,4 @@ module PayHyper
|
|
96
155
|
end
|
97
156
|
end
|
98
157
|
|
99
|
-
def self.check_ani_authenticity(request)
|
100
|
-
raise_if_not_setup!
|
101
|
-
authorization = request.env["HTTP_AUTHORIZATION"]
|
102
|
-
return false unless authorization
|
103
|
-
matches = authorization.match(/\A(.*) (.*):(.*)/)
|
104
|
-
return false unless matches
|
105
|
-
method, access_key_id, input_signature = matches.captures
|
106
|
-
return false unless method == "Hyper" && access_key_id && input_signature && access_key_id == @access_key_id
|
107
|
-
request.env["rack.input"].rewind # In case someone forgot to rewind the input.
|
108
|
-
body = request.env["rack.input"].read
|
109
|
-
request.env["rack.input"].rewind # Be nice to others.
|
110
|
-
canonical_request_representation = [request.env["REQUEST_METHOD"], request.env["HTTP_HOST"], request.env["PATH_INFO"], request.env["CONTENT_TYPE"], body].join("\n") # TODO: security bug if the webserver doesn't check host headers.
|
111
|
-
correct_signature = Security.sign(@access_key_secret, canonical_request_representation)
|
112
|
-
return Security.secure_compare(correct_signature, input_signature)
|
113
|
-
end
|
114
|
-
|
115
|
-
def self.parse_notification(request)
|
116
|
-
raise_if_not_setup!
|
117
|
-
if check_ani_authenticity(request)
|
118
|
-
request.env["rack.input"].rewind # In case someone forgot to rewind the input.
|
119
|
-
body = request.env["rack.input"].read
|
120
|
-
request.env["rack.input"].rewind # Be nice to others.
|
121
|
-
JSON.load(body)
|
122
|
-
else
|
123
|
-
nil
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
class PayHyperError < StandardError; end
|
128
|
-
class ValidationError < PayHyperError; end
|
129
|
-
class CommunicationError < PayHyperError; end
|
130
158
|
end
|
data/payhyper.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
|
|
6
6
|
|
7
7
|
s.name = 'payhyper'
|
8
8
|
s.version = PayHyper::VERSION
|
9
|
-
s.date = '
|
9
|
+
s.date = '2014-04-26'
|
10
10
|
s.summary = 'The Ruby bindings of the Hyper API'
|
11
11
|
s.description = 'Hyper is an API for cash collection. See http://payhyper.com for more.'
|
12
12
|
s.authors = ["Sinan Taifour"]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: payhyper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sinan Taifour
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-04-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
@@ -28,7 +28,7 @@ dependencies:
|
|
28
28
|
name: multi_json
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 1.0.4
|
34
34
|
- - <
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
|
-
- -
|
41
|
+
- - '>='
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: 1.0.4
|
44
44
|
- - <
|
@@ -65,17 +65,17 @@ require_paths:
|
|
65
65
|
- lib
|
66
66
|
required_ruby_version: !ruby/object:Gem::Requirement
|
67
67
|
requirements:
|
68
|
-
- -
|
68
|
+
- - '>='
|
69
69
|
- !ruby/object:Gem::Version
|
70
70
|
version: '0'
|
71
71
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - '>='
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
requirements: []
|
77
77
|
rubyforge_project:
|
78
|
-
rubygems_version: 2.
|
78
|
+
rubygems_version: 2.2.2
|
79
79
|
signing_key:
|
80
80
|
specification_version: 4
|
81
81
|
summary: The Ruby bindings of the Hyper API
|