pesapal 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: be6b9604e4788df7261b80d64ae81c03181af7b5
4
+ data.tar.gz: 08721ecf0cd162eeca31abe10a448477bd482ed1
5
+ SHA512:
6
+ metadata.gz: 533b27e99df804b0b7678b2e03ca495cb57c4ef537ffdb6d1b50c29e5fdc868b915694ec683c2f091b86c92e8dd634300bad094a3ec67f02ad414088361cefea
7
+ data.tar.gz: 5631b6072f4ce540e87cc7a00864c9ab4a7b66898c42f1b54b4d84cde00aa23882e5fe385ca7605779a57e80f8155544bc0ac2a44f3098816b6721a87c18a2e6
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ # Ignore bundler config #
2
+ /.bundle
3
+
4
+ # Ignore bundled gems #
5
+ /vendor/bundle
6
+
7
+ # Ignore all logfiles and tempfiles #
8
+ /log/*
9
+ /tmp/*
10
+
11
+ # Other Files #
12
+ *.gem
13
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pesapal.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 King'ori Maina
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,119 @@
1
+ Pesapal RubyGem
2
+ ===============
3
+
4
+ Make authenticated Pesapal API calls without the fuss! Handles all the [oAuth
5
+ stuff][1] abstracting any direct interaction with the API endpoints so that you
6
+ can focus on what matters. _Building awesome_.
7
+
8
+ This gem is work in progress. At the moment, the only functionality built-in is
9
+ posting an order i.e. fetching the URL that is required to display the post-
10
+ order iframe. Everything else should be easy to do as the groundwork has already
11
+ been laid. If you are [feeling generous and want to contribute, feel free][9].
12
+
13
+ Submit [issues and requests here][6]. The gem should be [up on RubyGems.org][7].
14
+
15
+ _Ps: No 3rd party oAuth library dependencies, it handles all the oAuth flows on
16
+ it's own so it's light on your app._
17
+
18
+
19
+ Installation
20
+ ------------
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ gem 'pesapal'
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install pesapal
33
+
34
+
35
+ Usage
36
+ -----
37
+
38
+ ### Setup ###
39
+
40
+ Initialize Pesapal object and choose the mode, there are two modes;
41
+ `:development` and `:production`. They determine if you the code will interact
42
+ with Pesapal for testing or for a live deployment.
43
+
44
+ ```ruby
45
+ # initiate pesapal object set to development mode
46
+ pesapal = Pesapal::Merchant.new(:development)
47
+ ```
48
+
49
+ Now set the Pesapal credentials. This assumes that you've chosen the appropriate
50
+ credentials as they differ based on the mode chosen above (Pesapal provide the
51
+ keys). Replace the placeholders below with your own credentials.
52
+
53
+ ```ruby
54
+ # set pesapal api credentials
55
+ pesapal.credentials = { :consumer_key => '<YOUR_CONSUMER_KEY>',
56
+ :consumer_secret => '<YOUR_CONSUMER_SECRET>'
57
+ }
58
+ ```
59
+
60
+ ### Post Order ###
61
+
62
+ Once you've set up the credentials, set up the order details in a hash as shown
63
+ in the example below ... all keys **MUST** be present. If there's one that you
64
+ wish to ignore just leave it with a blank string but make sure it's included
65
+ e.g. the phonenumber.
66
+
67
+ ```ruby
68
+ #set order details
69
+ pesapal.order_details = { :amount => 1000,
70
+ :description => 'this is the transaction description',
71
+ :type => 'MERCHANT',
72
+ :reference => 808-707-606,
73
+ :first_name => 'Swaleh',
74
+ :last_name => 'Mdoe',
75
+ :email => 'user@example.com',
76
+ :phonenumber => '+254722222222'
77
+ }
78
+ ```
79
+
80
+ Then generate the transaction url as below. In the example, the value is
81
+ assigned to the variable `order_url` which you can pass on to the templating
82
+ system of your to generate an iframe.
83
+
84
+ ```ruby
85
+ # generate transaction url
86
+ order_url = pesapal.generate_order_url
87
+ ```
88
+
89
+
90
+ Contributing
91
+ ------------
92
+
93
+ 1. [Fork it][8]
94
+ 2. Create your feature branch (`git checkout -b wip-my-new-feature`)
95
+ 3. Commit your changes (`git commit -am 'Add some feature with awesome'`)
96
+ 4. Push to the branch (`git push origin wip-my-new-feature`)
97
+ 5. Create new pull request
98
+
99
+ _Ps: Please prefix branch name with 'wip-' ... means 'work in progress'._
100
+
101
+
102
+ References
103
+ ----------
104
+
105
+ * [oAuth 1.0 Spec][1]
106
+ * [Developing a RubyGem using Bundler][2]
107
+ * [Make your own gem][3]
108
+ * [Pesapal API Reference (Official)][4]
109
+ * [Pesapal PHP API Reference (Unofficial)][5]
110
+
111
+ [1]: http://oauth.net/core/1.0/
112
+ [2]: https://github.com/radar/guides/blob/master/gem-development.md
113
+ [3]: http://guides.rubygems.org/make-your-own-gem/
114
+ [4]: http://developer.pesapal.com/how-to-integrate/api-reference
115
+ [5]: https://github.com/itsmrwave/pesapal-php#pesapal-php-api-reference-unofficial
116
+ [6]: https://github.com/itsmrwave/pesapal-rubygem/issues
117
+ [7]: http://rubygems.org/gems/pesapal
118
+ [8]: https://github.com/itsmrwave/pesapal-rubygem/fork
119
+ [9]: https://github.com/itsmrwave/pesapal-rubygem#contributing
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/lib/pesapal.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "htmlentities"
2
+ require "pesapal/merchant"
3
+ require "pesapal/merchant/post"
4
+ require "pesapal/oauth"
5
+ require "pesapal/version"
6
+
@@ -0,0 +1,114 @@
1
+ module Pesapal
2
+
3
+ class Merchant
4
+
5
+ attr_accessor :callback_url, :credentials, :order_details
6
+ attr_reader :api_domain, :api_endpoints
7
+
8
+ def api_domain
9
+ @api_domain
10
+ end
11
+
12
+ def api_endpoints
13
+ @api_endpoints
14
+ end
15
+
16
+ def callback_url
17
+ @callback_url
18
+ end
19
+
20
+ def credentials
21
+ @credentials
22
+ end
23
+
24
+ def order_details
25
+ @order_details
26
+ end
27
+
28
+ private
29
+
30
+ def params
31
+ @params
32
+ end
33
+
34
+ def post_xml
35
+ @post_xml
36
+ end
37
+
38
+ def token_secret
39
+ @token_secret
40
+ end
41
+
42
+ public
43
+
44
+ # constructor
45
+ def initialize(mode = :development)
46
+
47
+ # convert symbol to string and downcase
48
+ mode.to_s.downcase!
49
+
50
+ # initialize
51
+ @params = nil
52
+ @post_xml = nil
53
+ @token_secret = nil
54
+
55
+ # set the credentials from the config (if initializers/pesapal.rb
56
+ # exists they should have set these values)
57
+ @credentials = nil
58
+
59
+ # set the callback url that the iframe will respond to
60
+ @callback_url = 'http://0.0.0.0:3000/pesapal/callback'
61
+
62
+ # set api endpoints depending on the mode
63
+ @api_endpoints = {}
64
+ if mode == 'development'
65
+ set_endpoints_development
66
+ elseif mode == 'production'
67
+ set_endpoints_production
68
+ else
69
+ set_endpoints_development
70
+ end
71
+ end
72
+
73
+ # generate pesapal order url (often iframed)
74
+ def generate_order_url
75
+
76
+ # build xml with input data, the format is standard so no editing is
77
+ # required
78
+ @post_xml = Pesapal::Post::generate_post_xml @order_details
79
+
80
+ # initialize setting of @params (oauth_signature left empty) ... this gene
81
+ @params = Pesapal::Post::set_parameters(@callback_url, @credentials[:consumer_key], @post_xml)
82
+
83
+ # generate oauth signature and add signature to the request parameters
84
+ @params[:oauth_signature] = Pesapal::Oauth::generate_oauth_signature("GET", @api_endpoints[:postpesapaldirectorderv4], @params, @credentials[:consumer_secret], @token_secret)
85
+
86
+ # change params (with signature) to a query string
87
+ query_string = Pesapal::Oauth::generate_encoded_params_query_string @params
88
+
89
+ "#{@api_endpoints[:postpesapaldirectorderv4]}?#{query_string}"
90
+ end
91
+
92
+ private
93
+
94
+ # set all endpoint for use in development mode
95
+ def set_endpoints_development
96
+ @api_domain = 'http://demo.pesapal.com'
97
+ set_endpoints @api_domain
98
+ end
99
+
100
+ # set all enpoints for use in production mode
101
+ def set_endpoints_production
102
+ @api_domain = "https://www.pesapal.com"
103
+ set_endpoints @api_domain
104
+ end
105
+
106
+ # set endpoints
107
+ def set_endpoints(domain_string)
108
+ @api_endpoints[:postpesapaldirectorderv4] = "#{domain_string}/API/PostPesapalDirectOrderV4"
109
+ @api_endpoints[:querypaymentstatus] = "#{domain_string}/API/QueryPaymentStatus"
110
+ @api_endpoints[:querypaymentstatusbymerchantref] = "#{domain_string}/API/QueryPaymentStatus"
111
+ @api_endpoints[:querypaymentdetails] = "#{domain_string}/API/QueryPaymentDetails"
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,50 @@
1
+ module Pesapal
2
+
3
+ module Post
4
+
5
+ # build html encoded xml string for PostPesapalDirectOrderV4
6
+ def Post.generate_post_xml(details)
7
+
8
+ # build xml with input data, the format is standard so no editing is
9
+ # required
10
+ post_xml = ''
11
+ post_xml.concat '<?xml version="1.0" encoding="utf-8"?>'
12
+ post_xml.concat '<PesapalDirectOrderInfo '
13
+ post_xml.concat 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
14
+ post_xml.concat 'xmlns:xsd="http://www.w3.org/2001/XMLSchema" '
15
+ post_xml.concat "Amount=\"#{details[:amount]}\" "
16
+ post_xml.concat "Description=\"#{details[:description]}\" "
17
+ post_xml.concat "Type=\"#{details[:type]}\" "
18
+ post_xml.concat "Reference=\"#{details[:reference]}\" "
19
+ post_xml.concat "FirstName=\"#{details[:first_name]}\" "
20
+ post_xml.concat "LastName=\"#{details[:last_name]}\" "
21
+ post_xml.concat "Email=\"#{details[:email]}\" "
22
+ post_xml.concat "PhoneNumber=\"#{details[:phonenumber]}\" "
23
+ post_xml.concat 'xmlns="http://www.pesapal.com" />'
24
+
25
+ encoder = HTMLEntities.new(:xhtml1)
26
+ post_xml = encoder.encode post_xml
27
+
28
+ "#{post_xml}"
29
+ end
30
+
31
+ # set parameters required by the PostPesapalDirectOrderV4
32
+ def Post.set_parameters(callback_url, consumer_key, post_xml)
33
+
34
+ # parameters required by the PostPesapalDirectOrderV4 call (excludes
35
+ # oauth_signature parameter as per the instructions here
36
+ # http://developer.pesapal.com/how-to-integrate/api-reference#PostPesapalDirectOrderV4)
37
+
38
+ timestamp = Time.now.to_i.to_s
39
+
40
+ params = { :oauth_callback => callback_url,
41
+ :oauth_consumer_key => consumer_key,
42
+ :oauth_nonce => "#{timestamp}" + Pesapal::Oauth.generate_nonce(12),
43
+ :oauth_signature_method => 'HMAC-SHA1',
44
+ :oauth_timestamp => "#{timestamp}",
45
+ :oauth_version => '1.0',
46
+ :pesapal_request_data => post_xml
47
+ }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,178 @@
1
+ module Pesapal
2
+
3
+ module Oauth
4
+
5
+ # generate query string from parameters hash
6
+ def Oauth.generate_encoded_params_query_string(params = {})
7
+
8
+ # 1) percent encode every key and value that will be signed
9
+ # 2) sort the list of parameters alphabetically by encoded key
10
+ # 3) for each key/value pair
11
+ # - append the encoded key to the output string
12
+ # - append the '=' character to the output string
13
+ # - append the encoded value to the output string
14
+ # 4) if there are more key/value pairs remaining, append a '&'
15
+ # character to the output string
16
+
17
+ # the oauth spec says to sort lexigraphically, which is the default
18
+ # alphabetical sort for many libraries. in case of two parameters
19
+ # with the same encoded key, the oauth spec says to continue
20
+ # sorting based on value
21
+
22
+ queries = []
23
+ params.each do |k,v| queries.push "#{self.parameter_encode(k.to_s)}=#{self.parameter_encode(v.to_s)}" end
24
+
25
+ # parameters are sorted by name, using lexicographical byte value
26
+ # ordering
27
+ queries.sort!
28
+
29
+ queries.join('&')
30
+ end
31
+
32
+ # generate oauth nonce
33
+ def Oauth.generate_nonce(length)
34
+
35
+ # the consumer shall then generate a nonce value that is unique for
36
+ # all requests with that timestamp. a nonce is a random string,
37
+ # uniquely generated for each request. the nonce allows the service
38
+ # provider to verify that a request has never been made before and
39
+ # helps prevent replay attacks when requests are made over a non-
40
+ # secure channel (such as http).
41
+
42
+ chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
43
+ nonce = ''
44
+ length.times { nonce << chars[rand(chars.size)] }
45
+
46
+ "#{nonce}"
47
+ end
48
+
49
+ # generate the oauth signature using hmac-sha1 algorithm
50
+ def Oauth.generate_oauth_signature(http_method, absolute_url, params, consumer_secret, token_secret = nil)
51
+
52
+ # the signature is calculated by passing the signature base string
53
+ # and signing key to the hmac-sha1 hashing algorithm. the output of
54
+ # the hmac signing function is a binary string. this needs to be
55
+ # base64 encoded to produce the signature string.
56
+
57
+ # for pesapal flow we don't have a token secret to we will set as
58
+ # nil and the appropriate action will be taken as per the oauth
59
+ # spec. see notes in the method that creates signing keys
60
+
61
+ # prepare the values we need
62
+ digest = OpenSSL::Digest::Digest.new('sha1')
63
+ signature_base_string = self.generate_signature_base_string(http_method, absolute_url, params)
64
+ signing_key = self.generate_signing_key(consumer_secret, token_secret)
65
+
66
+ hmac = OpenSSL::HMAC.digest(digest, signing_key, signature_base_string)
67
+ Base64.encode64(hmac).chomp
68
+ end
69
+
70
+ # generate query string from signable parameters hash
71
+ def Oauth.generate_signable_encoded_params_query_string(params = {})
72
+
73
+ # oauth_signature parameter MUST be excluded, assumes it was already
74
+ # initialized by calling set_parameters
75
+ params.delete(:oauth_signature)
76
+
77
+ self.generate_encoded_params_query_string params
78
+ end
79
+
80
+ # generate the oauth signature
81
+ def Oauth.generate_signature_base_string(http_method, absolute_url, params)
82
+
83
+ # three values collected so far must be joined to make a single
84
+ # string, from which the signature will be generated. This is
85
+ # called the signature base string by the OAuth specification
86
+
87
+ # step 1: convert the http method to uppercase
88
+ http_method = http_method.upcase
89
+
90
+ # step 2: percent encode the url
91
+ url_encoded = self.parameter_encode(self.normalized_request_uri(absolute_url))
92
+
93
+ # step 3: percent encode the parameter string
94
+ parameter_string_encoded = self.parameter_encode(self.generate_signable_encoded_params_query_string params)
95
+
96
+ # the signature base string should contain exactly 2 ampersand '&'
97
+ # characters. The percent '%' characters in the parameter string should
98
+ # be encoded as %25 in the signature base string
99
+
100
+ "#{http_method}&#{url_encoded}&#{parameter_string_encoded}"
101
+ end
102
+
103
+ # generate signing key
104
+ def Oauth.generate_signing_key(consumer_secret, token_secret = nil)
105
+
106
+ # the signing key is simply the percent encoded consumer secret,
107
+ # followed by an ampersand character '&', followed by the percent
108
+ # encoded token secret
109
+
110
+ # note that there are some flows, such as when obtaining a request
111
+ # token, where the token secret is not yet known. In this case, the
112
+ # signing key should consist of the percent encoded consumer secret
113
+ # followed by an ampersand character '&'
114
+
115
+ # "#{@credentials[:consumer_secret]}"
116
+ consumer_secret_encoded = self.parameter_encode(consumer_secret)
117
+
118
+ token_secret_encoded = ""
119
+ unless token_secret.nil?
120
+ token_secret_encoded = self.parameter_encode(token_secret)
121
+ end
122
+
123
+ "#{consumer_secret_encoded}&#{token_secret_encoded}"
124
+ end
125
+
126
+ # normalize request absolute URL
127
+ def Oauth.normalized_request_uri(absolute_url)
128
+
129
+ # the signature base string includes the request absolute url, tying
130
+ # the signature to a specific endpoint. the url used in the
131
+ # signature base string must include the scheme, authority, and
132
+ # path, and must exclude the query and fragment as defined by
133
+ # [rfc3986] section 3.
134
+
135
+ # if the absolute request url is not available to the service
136
+ # provider (it is always available to the consumer), it can be
137
+ # constructed by combining the scheme being used, the http host
138
+ # header, and the relative http request url. if the host header is
139
+ # not available, the service provider should use the host name
140
+ # communicated to the consumer in the documentation or other means.
141
+
142
+ # the service provider should document the form of url used in the
143
+ # signature base string to avoid ambiguity due to url normalization.
144
+ # unless specified, url scheme and authority must be lowercase and
145
+ # include the port number; http default port 80 and https default
146
+ # port 443 must be excluded.
147
+
148
+ u = URI.parse(absolute_url)
149
+
150
+ scheme = u.scheme.downcase
151
+ host = u.host.downcase
152
+ path = u.path
153
+ port = u.port
154
+
155
+ port = (scheme == 'http' && port != 80) || (scheme == 'https' && port != 443) ? ":#{port}" : ""
156
+ path = (path && path != '') ? path : '/'
157
+
158
+ "#{scheme}://#{host}#{port}#{path}"
159
+ end
160
+
161
+ # percentage encode value as per the oauth spec
162
+ def Oauth.parameter_encode(string)
163
+
164
+ # all parameter names and values are escaped using the [rfc3986]
165
+ # percent-encoding (%xx) mechanism. characters not in the unreserved
166
+ # character set ([rfc3986] section 2.3) must be encoded. characters
167
+ # in the unreserved character set must not be encoded. hexadecimal
168
+ # characters in encodings must be upper case. text names and values
169
+ # must be encoded as utf-8 octets before percent-encoding them per
170
+ # [rfc3629].
171
+
172
+ # reserved character regexp, per section 5.1
173
+ reserved_characters = /[^a-zA-Z0-9\-\.\_\~]/
174
+
175
+ URI::escape(string.to_s.force_encoding(Encoding::UTF_8), reserved_characters)
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,3 @@
1
+ module Pesapal
2
+ VERSION = "0.0.1"
3
+ end
data/pesapal.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "pesapal/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "pesapal"
7
+ spec.version = Pesapal::VERSION
8
+ spec.date = "2013-09-28"
9
+ spec.authors = ["Job King'ori Maina"]
10
+ spec.email = ["j@kingori.co"]
11
+ spec.description = "Make authenticated Pesapal API calls without the fuss!"
12
+ spec.summary = "Make authenticated Pesapal API calls without the fuss! Handles all the oAuth stuff abstracting any direct interaction with the API endpoints so that you can focus on what matters. Building awesome."
13
+ spec.homepage = "http://rubygems.org/gems/pesapal"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pesapal
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Job King'ori Maina
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Make authenticated Pesapal API calls without the fuss!
42
+ email:
43
+ - j@kingori.co
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - lib/pesapal.rb
54
+ - lib/pesapal/merchant.rb
55
+ - lib/pesapal/merchant/post.rb
56
+ - lib/pesapal/oauth.rb
57
+ - lib/pesapal/version.rb
58
+ - pesapal.gemspec
59
+ homepage: http://rubygems.org/gems/pesapal
60
+ licenses:
61
+ - MIT
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.1.5
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Make authenticated Pesapal API calls without the fuss! Handles all the oAuth
83
+ stuff abstracting any direct interaction with the API endpoints so that you can
84
+ focus on what matters. Building awesome.
85
+ test_files: []