mpesarb 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e9d8b053eedae0cab3d4839a9a618f7b4f520b2deada034c07ab57358d69896b
4
+ data.tar.gz: da6f1486a2a3e329dc0999b0cb901791b97c4fe87caf1f85e364fdd864cec069
5
+ SHA512:
6
+ metadata.gz: d05e129b9e523fc31be44cb452283aa83993086b67b7cb540ce0832db3ba787a000c6baee3617f4529e34d6e7668ad31bbf97b78f5aa2e1fb9de73764ea326a5
7
+ data.tar.gz: a07ec8dc4b8d383028952722b5785fbba6884d640a0b5333005c6b1905015cba00b6678b30eeebb7cdce5e429cb3b71832a157c7eba149216fae652c5c94577b
@@ -0,0 +1,20 @@
1
+ name: Mpesa_Gem
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+
8
+ runs-on: ubuntu-latest
9
+
10
+ steps:
11
+ - uses: actions/checkout@v1
12
+ - name: Set up Ruby 2.6
13
+ uses: actions/setup-ruby@v1
14
+ with:
15
+ ruby-version: 2.6.x
16
+ - name: Build and test with Rake
17
+ run: |
18
+ gem install bundler
19
+ bundle install --jobs 4 --retry 3
20
+ bundle exec rake
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ coverage
3
+ pkg
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.0
6
+ before_install: gem install bundler -v 2.1.0.pre.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ ### Unreleased
2
+ - Update gemspec
3
+ - Read certificate full path
4
+ - Return early if get access token fail
5
+ ### 2020-12-09
6
+ - Reset configuration before new configuration
7
+ - Encrypt initiator password with X506 Certificate key
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at TODO: Write your email address. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [https://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: https://contributor-covenant.org
74
+ [version]: https://contributor-covenant.org/version/1/4/
data/Dockerfile ADDED
@@ -0,0 +1,25 @@
1
+ FROM ruby:rc-alpine3.10
2
+ # update and upgrade packages
3
+ RUN apk update && apk upgrade
4
+
5
+ # Create non-root user
6
+ RUN addgroup -S admin -g 1000 && adduser -S -g '' -u 1000 -G admin deploy
7
+
8
+ # make a parrent directory
9
+ RUN mkdir -p /mpesa
10
+
11
+ # let deploy user own the directory
12
+ RUN chown deploy /mpesa
13
+
14
+ # set the deploy user
15
+ USER deploy
16
+ # set the directory as working DIR
17
+ WORKDIR /mpesa
18
+
19
+ # install gem bundler
20
+ RUN gem install bundler
21
+
22
+ # create a Gem
23
+ #RUN bundle gem ruby_mpesa
24
+
25
+ COPY --chown=deploy:admin . /mpesa
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in mpesa.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,103 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mpesa (0.2.0)
5
+ faraday (>= 1.1)
6
+ faraday_middleware (~> 1.1)
7
+ openssl (>= 2.1)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ addressable (2.8.0)
13
+ public_suffix (>= 2.0.2, < 5.0)
14
+ ansi (1.5.0)
15
+ builder (3.2.4)
16
+ byebug (11.1.3)
17
+ coderay (1.1.3)
18
+ coveralls (0.8.23)
19
+ json (>= 1.8, < 3)
20
+ simplecov (~> 0.16.1)
21
+ term-ansicolor (~> 1.3)
22
+ thor (>= 0.19.4, < 2.0)
23
+ tins (~> 1.6)
24
+ crack (0.4.5)
25
+ rexml
26
+ docile (1.4.0)
27
+ faraday (1.7.1)
28
+ faraday-em_http (~> 1.0)
29
+ faraday-em_synchrony (~> 1.0)
30
+ faraday-excon (~> 1.1)
31
+ faraday-httpclient (~> 1.0.1)
32
+ faraday-net_http (~> 1.0)
33
+ faraday-net_http_persistent (~> 1.1)
34
+ faraday-patron (~> 1.0)
35
+ faraday-rack (~> 1.0)
36
+ multipart-post (>= 1.2, < 3)
37
+ ruby2_keywords (>= 0.0.4)
38
+ faraday-em_http (1.0.0)
39
+ faraday-em_synchrony (1.0.0)
40
+ faraday-excon (1.1.0)
41
+ faraday-httpclient (1.0.1)
42
+ faraday-net_http (1.0.1)
43
+ faraday-net_http_persistent (1.2.0)
44
+ faraday-patron (1.0.0)
45
+ faraday-rack (1.0.0)
46
+ faraday_middleware (1.1.0)
47
+ faraday (~> 1.0)
48
+ hashdiff (1.0.1)
49
+ json (2.5.1)
50
+ method_source (1.0.0)
51
+ minitest (5.14.4)
52
+ minitest-reporters (1.4.3)
53
+ ansi
54
+ builder
55
+ minitest (>= 5.0)
56
+ ruby-progressbar
57
+ multipart-post (2.1.1)
58
+ openssl (2.2.0)
59
+ pry (0.13.1)
60
+ coderay (~> 1.1)
61
+ method_source (~> 1.0)
62
+ pry-byebug (3.9.0)
63
+ byebug (~> 11.0)
64
+ pry (~> 0.13.0)
65
+ public_suffix (4.0.6)
66
+ rake (13.0.6)
67
+ rexml (3.2.5)
68
+ ruby-progressbar (1.11.0)
69
+ ruby2_keywords (0.0.5)
70
+ simplecov (0.16.1)
71
+ docile (~> 1.1)
72
+ json (>= 1.8, < 3)
73
+ simplecov-html (~> 0.10.0)
74
+ simplecov-html (0.10.2)
75
+ sync (0.5.0)
76
+ term-ansicolor (1.7.1)
77
+ tins (~> 1.0)
78
+ thor (1.1.0)
79
+ tins (1.29.1)
80
+ sync
81
+ vcr (6.0.0)
82
+ webmock (3.14.0)
83
+ addressable (>= 2.8.0)
84
+ crack (>= 0.3.2)
85
+ hashdiff (>= 0.4.0, < 2.0.0)
86
+
87
+ PLATFORMS
88
+ x86_64-darwin-19
89
+
90
+ DEPENDENCIES
91
+ bundler (>= 2.1.4)
92
+ byebug
93
+ coveralls
94
+ minitest
95
+ minitest-reporters
96
+ mpesa!
97
+ pry-byebug
98
+ rake (>= 12.3)
99
+ vcr
100
+ webmock (~> 3.7)
101
+
102
+ BUNDLED WITH
103
+ 2.2.17
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # Mpesa
2
+
3
+ Welcome to [mpesa](https://developer.safaricom.co.ke/) API gem. The gem defines the API resources and helps developers to make requests cleanly.
4
+
5
+ When you receive a JSON response from an API endpoint, it's really easy to convert this to a Ruby hash. But hashes don't feel very Ruby-ish when you're working with them.
6
+
7
+ To help on this gem parse the responses to `OpenStruct` Objects so a developer can interact with the response just like regular ruby objects we are used to.
8
+
9
+ This Gem provides an interface that developers can use to convert JSON to `OpenStruct` objects, this is useful when you want to parse results callbacks data.
10
+
11
+ ## Installation
12
+
13
+ Install via `Gemfile`
14
+ ```
15
+ gem "mpesa", github: "gathuku/mpesa"
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ### Initialization
21
+
22
+ ```ruby
23
+ client = Mpesa::Client.new(key: "SKKSS" , secret: "SJSKS", env: "sandbox", adapter: )
24
+
25
+ response = client.auth
26
+ response.access_token # XiKf3D6UrY0J8S2aeOQ7R7w0BuA5
27
+ response.expires_in # 3599
28
+ ```
29
+
30
+ ### Register Urls
31
+
32
+ Register C2B Urls( confirmation and validation url)
33
+ ```ruby
34
+ response = client.register(
35
+ shortcode: "44445",
36
+ confirmation_url: 'http://test.com', validation_url: 'http://test.com'
37
+ )
38
+ response.OriginatorCoversationID # "807-15591582-1"
39
+ response.ResponseCode # "0"
40
+ response.ResponseDescription # "success"
41
+ ```
42
+
43
+ ### STK (LPNMO)
44
+
45
+ Lipa na mpesa online(Stk Push)
46
+
47
+ ```ruby
48
+ response = client.stk(
49
+ shortcode: "174379",
50
+ pass_key: "bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919", # Optional if passed in client initialization
51
+ amount: "10",
52
+ phone: "254705112855",
53
+ callback_url: "https://test.com",
54
+ reference: "REF",
55
+ trans_desc: "desc"
56
+ )
57
+
58
+ response.CheckoutRequestID # "ws_CO_040920212326513616"
59
+ response.inspect # to see all available attributes
60
+ ```
61
+
62
+
63
+ ### B2C (Payout)
64
+
65
+ ```rb
66
+ response = client.payout(
67
+ shortcode: "600998", # Optional if added in client initialization
68
+ initiator_username: "testapi",
69
+ initiator_password: "Safaricom998!",
70
+ command_id: "BusinessPayment",
71
+ phone: "254708374149",
72
+ amount: "100",
73
+ result_url: "https://example.com/result",
74
+ timeout_url: "https://example.com/result",
75
+ occasion: "some desc",
76
+ remarks: "remarks"
77
+ )
78
+
79
+ response.ConversationID # AG_20210904_0000574b3c8d93651740
80
+ response.OriginatorConversationID # "28831-15819693-1"
81
+ respose.ResponseDescription # "Accept the service request successfully."
82
+
83
+ ```
84
+
85
+
86
+ ## Development
87
+
88
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
89
+
90
+ To install this gem onto your local machine, run `bundle exec rake install`.
91
+
92
+ ## Contributing
93
+
94
+ Bug reports and pull requests are welcome on GitHub at https://github.com/gathuku/mpesa. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/gathuku/mpesa/blob/master/CODE_OF_CONDUCT.md).
95
+
96
+
97
+ ## License
98
+
99
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
100
+
101
+ ## Code of Conduct
102
+
103
+ Everyone interacting in the Mpesa project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/gathuku/mpesa/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'mpesa'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ client = Mpesa::Client.new(key: 'ZtkRW6ATbVtFpNml5w5SfG26Adfyagn9', secret: 'dosFI1yQ8bvHEVFw', env: 'sandbox')
14
+
15
+ require 'irb'
16
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,6 @@
1
+ version: "3"
2
+ services:
3
+ app:
4
+ build: .
5
+ volumes:
6
+ - .:/mpesa
@@ -0,0 +1,38 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIGkzCCBXugAwIBAgIKXfBp5gAAAD+hNjANBgkqhkiG9w0BAQsFADBbMRMwEQYK
3
+ CZImiZPyLGQBGRYDbmV0MRkwFwYKCZImiZPyLGQBGRYJc2FmYXJpY29tMSkwJwYD
4
+ VQQDEyBTYWZhcmljb20gSW50ZXJuYWwgSXNzdWluZyBDQSAwMjAeFw0xNzA0MjUx
5
+ NjA3MjRaFw0xODAzMjExMzIwMTNaMIGNMQswCQYDVQQGEwJLRTEQMA4GA1UECBMH
6
+ TmFpcm9iaTEQMA4GA1UEBxMHTmFpcm9iaTEaMBgGA1UEChMRU2FmYXJpY29tIExp
7
+ bWl0ZWQxEzARBgNVBAsTClRlY2hub2xvZ3kxKTAnBgNVBAMTIGFwaWdlZS5hcGlj
8
+ YWxsZXIuc2FmYXJpY29tLmNvLmtlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
9
+ CgKCAQEAoknIb5Tm1hxOVdFsOejAs6veAai32Zv442BLuOGkFKUeCUM2s0K8XEsU
10
+ t6BP25rQGNlTCTEqfdtRrym6bt5k0fTDscf0yMCoYzaxTh1mejg8rPO6bD8MJB0c
11
+ FWRUeLEyWjMeEPsYVSJFv7T58IdAn7/RhkrpBl1dT7SmIZfNVkIlD35+Cxgab+u7
12
+ +c7dHh6mWguEEoE3NbV7Xjl60zbD/Buvmu6i9EYz+27jNVPI6pRXHvp+ajIzTSsi
13
+ eD8Ztz1eoC9mphErasAGpMbR1sba9bM6hjw4tyTWnJDz7RdQQmnsW1NfFdYdK0qD
14
+ RKUX7SG6rQkBqVhndFve4SDFRq6wvQIDAQABo4IDJDCCAyAwHQYDVR0OBBYEFG2w
15
+ ycrgEBPFzPUZVjh8KoJ3EpuyMB8GA1UdIwQYMBaAFOsy1E9+YJo6mCBjug1evuh5
16
+ TtUkMIIBOwYDVR0fBIIBMjCCAS4wggEqoIIBJqCCASKGgdZsZGFwOi8vL0NOPVNh
17
+ ZmFyaWNvbSUyMEludGVybmFsJTIwSXNzdWluZyUyMENBJTIwMDIsQ049U1ZEVDNJ
18
+ U1NDQTAxLENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2
19
+ aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPXNhZmFyaWNvbSxEQz1uZXQ/Y2VydGlm
20
+ aWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1
21
+ dGlvblBvaW50hkdodHRwOi8vY3JsLnNhZmFyaWNvbS5jby5rZS9TYWZhcmljb20l
22
+ MjBJbnRlcm5hbCUyMElzc3VpbmclMjBDQSUyMDAyLmNybDCCAQkGCCsGAQUFBwEB
23
+ BIH8MIH5MIHJBggrBgEFBQcwAoaBvGxkYXA6Ly8vQ049U2FmYXJpY29tJTIwSW50
24
+ ZXJuYWwlMjBJc3N1aW5nJTIwQ0ElMjAwMixDTj1BSUEsQ049UHVibGljJTIwS2V5
25
+ JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1zYWZh
26
+ cmljb20sREM9bmV0P2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0
27
+ aWZpY2F0aW9uQXV0aG9yaXR5MCsGCCsGAQUFBzABhh9odHRwOi8vY3JsLnNhZmFy
28
+ aWNvbS5jby5rZS9vY3NwMAsGA1UdDwQEAwIFoDA9BgkrBgEEAYI3FQcEMDAuBiYr
29
+ BgEEAYI3FQiHz4xWhMLEA4XphTaE3tENhqCICGeGwcdsg7m5awIBZAIBDDAdBgNV
30
+ HSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwJwYJKwYBBAGCNxUKBBowGDAKBggr
31
+ BgEFBQcDAjAKBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAQEAC/hWx7KTwSYr
32
+ x2SOyyHNLTRmCnCJmqxA/Q+IzpW1mGtw4Sb/8jdsoWrDiYLxoKGkgkvmQmB2J3zU
33
+ ngzJIM2EeU921vbjLqX9sLWStZbNC2Udk5HEecdpe1AN/ltIoE09ntglUNINyCmf
34
+ zChs2maF0Rd/y5hGnMM9bX9ub0sqrkzL3ihfmv4vkXNxYR8k246ZZ8tjQEVsKehE
35
+ dqAmj8WYkYdWIHQlkKFP9ba0RJv7aBKb8/KP+qZ5hJip0I5Ey6JJ3wlEWRWUYUKh
36
+ gYoPHrJ92ToadnFCCpOlLKWc0xVxANofy6fqreOVboPO0qTAYpoXakmgeRNLUiar
37
+ 0ah6M/q/KA==
38
+ -----END CERTIFICATE-----
@@ -0,0 +1,37 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIGgDCCBWigAwIBAgIKMvrulAAAAARG5DANBgkqhkiG9w0BAQsFADBbMRMwEQYK
3
+ CZImiZPyLGQBGRYDbmV0MRkwFwYKCZImiZPyLGQBGRYJc2FmYXJpY29tMSkwJwYD
4
+ VQQDEyBTYWZhcmljb20gSW50ZXJuYWwgSXNzdWluZyBDQSAwMjAeFw0xNDExMTIw
5
+ NzEyNDVaFw0xNjExMTEwNzEyNDVaMHsxCzAJBgNVBAYTAktFMRAwDgYDVQQIEwdO
6
+ YWlyb2JpMRAwDgYDVQQHEwdOYWlyb2JpMRAwDgYDVQQKEwdOYWlyb2JpMRMwEQYD
7
+ VQQLEwpUZWNobm9sb2d5MSEwHwYDVQQDExhhcGljcnlwdC5zYWZhcmljb20uY28u
8
+ a2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCotwV1VxXsd0Q6i2w0
9
+ ugw+EPvgJfV6PNyB826Ik3L2lPJLFuzNEEJbGaiTdSe6Xitf/PJUP/q8Nv2dupHL
10
+ BkiBHjpQ6f61He8Zdc9fqKDGBLoNhNpBXxbznzI4Yu6hjBGLnF5Al9zMAxTij6wL
11
+ GUFswKpizifNbzV+LyIXY4RR2t8lxtqaFKeSx2B8P+eiZbL0wRIDPVC5+s4GdpFf
12
+ Y3QIqyLxI2bOyCGl8/XlUuIhVXxhc8Uq132xjfsWljbw4oaMobnB2KN79vMUvyoR
13
+ w8OGpga5VoaSFfVuQjSIf5RwW1hitm/8XJvmNEdeY0uKriYwbR8wfwQ3E0AIW1Fl
14
+ MMghAgMBAAGjggMkMIIDIDAdBgNVHQ4EFgQUwUfE+NgGndWDN3DyVp+CAiF1Zkgw
15
+ HwYDVR0jBBgwFoAU6zLUT35gmjqYIGO6DV6+6HlO1SQwggE7BgNVHR8EggEyMIIB
16
+ LjCCASqgggEmoIIBIoaB1mxkYXA6Ly8vQ049U2FmYXJpY29tJTIwSW50ZXJuYWwl
17
+ MjBJc3N1aW5nJTIwQ0ElMjAwMixDTj1TVkRUM0lTU0NBMDEsQ049Q0RQLENOPVB1
18
+ YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRp
19
+ b24sREM9c2FmYXJpY29tLERDPW5ldD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0
20
+ P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnSGR2h0dHA6Ly9j
21
+ cmwuc2FmYXJpY29tLmNvLmtlL1NhZmFyaWNvbSUyMEludGVybmFsJTIwSXNzdWlu
22
+ ZyUyMENBJTIwMDIuY3JsMIIBCQYIKwYBBQUHAQEEgfwwgfkwgckGCCsGAQUFBzAC
23
+ hoG8bGRhcDovLy9DTj1TYWZhcmljb20lMjBJbnRlcm5hbCUyMElzc3VpbmclMjBD
24
+ QSUyMDAyLENOPUFJQSxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2
25
+ aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPXNhZmFyaWNvbSxEQz1uZXQ/Y0FDZXJ0
26
+ aWZpY2F0ZT9iYXNlP29iamVjdENsYXNzPWNlcnRpZmljYXRpb25BdXRob3JpdHkw
27
+ KwYIKwYBBQUHMAGGH2h0dHA6Ly9jcmwuc2FmYXJpY29tLmNvLmtlL29jc3AwCwYD
28
+ VR0PBAQDAgWgMD0GCSsGAQQBgjcVBwQwMC4GJisGAQQBgjcVCIfPjFaEwsQDhemF
29
+ NoTe0Q2GoIgIZ4bBx2yDublrAgFkAgEMMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
30
+ BgEFBQcDATAnBgkrBgEEAYI3FQoEGjAYMAoGCCsGAQUFBwMCMAoGCCsGAQUFBwMB
31
+ MA0GCSqGSIb3DQEBCwUAA4IBAQBMFKlncYDI06ziR0Z0/reptIJRCMo+rqo/cUuP
32
+ KMmJCY3sXxFHs5ilNXo8YavgRLpxJxdZMkiUIVuVaBanXkz9/nMriiJJwwcMPjUV
33
+ 9nQqwNUEqrSx29L1ARFdUy7LhN4NV7mEMde3MQybCQgBjjOPcVSVZXnaZIggDYIU
34
+ w4THLy9rDmUIasC8GDdRcVM8xDOVQD/Pt5qlx/LSbTNe2fekhTLFIGYXJVz2rcsj
35
+ k1BfG7P3pXnsPAzu199UZnqhEF+y/0/nNpf3ftHZjfX6Ws+dQuLoDN6pIl8qmok9
36
+ 9E/EAgL1zOIzFvCRYlnjKdnsuqL1sIYFBlv3oxo6W1O+X9IZ
37
+ -----END CERTIFICATE-----
@@ -0,0 +1,48 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware'
3
+
4
+ module Mpesa
5
+ class Client
6
+ attr_reader :key, :secret, :env, :adapter, :shortcode, :pass_key
7
+
8
+ def initialize(key:, secret:, shortcode: nil, pass_key: nil, env: 'production', adapter: Faraday.default_adapter)
9
+ @key = key
10
+ @secret = secret
11
+ @env = env
12
+ @adapter = adapter
13
+ @pass_key = pass_key
14
+ @shortcode = shortcode
15
+ end
16
+
17
+ def auth
18
+ Token.new(self).token
19
+ end
20
+
21
+ def register(**args)
22
+ Register.new(self, args).call
23
+ end
24
+
25
+ def stk(**args)
26
+ Stk.new(self, args).call
27
+ end
28
+
29
+ def payout(**args)
30
+ Payout.new(self, args).call
31
+ end
32
+
33
+ def connection(basic_auth: false)
34
+ @connection ||= Faraday.new do |conn|
35
+ conn.url_prefix = "https://#{subdomain}.safaricom.co.ke"
36
+ conn.request :json
37
+ conn.response :json, content_type: 'application/json'
38
+ conn.adapter adapter
39
+ conn.request :basic_auth, key, secret if basic_auth
40
+ conn.request :authorization, :Bearer, auth.access_token unless basic_auth
41
+ end
42
+ end
43
+
44
+ def subdomain
45
+ env == 'production' ? 'api' : 'sandbox'
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ module Mpesa
2
+ class Error < StandardError; end
3
+ end
@@ -0,0 +1,18 @@
1
+ require 'ostruct'
2
+
3
+ module Mpesa
4
+ class Object
5
+ def initialize(attributes)
6
+ @attributes = OpenStruct.new(attributes)
7
+ end
8
+
9
+ def method_missing(method, *args, &block)
10
+ attribute = @attributes.send(method, *args, &block)
11
+ attribute.is_a?(Hash) ? Object.new(attribute) : attribute
12
+ end
13
+
14
+ def respond_to_missing?(_method, _include_private = false)
15
+ true
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,4 @@
1
+ module Mpesa
2
+ class Intance < Object
3
+ end
4
+ end
@@ -0,0 +1,34 @@
1
+ module Mpesa
2
+ class Resource
3
+ attr_reader :client, :args
4
+
5
+ def initialize(client, args = {})
6
+ @client = client
7
+ @args = args
8
+ end
9
+
10
+ def get_request(url:, params: {}, headers: {}, basic_auth: true)
11
+ handle_response client.connection(basic_auth: basic_auth).get(url, params, headers)
12
+ end
13
+
14
+ def post_request(url:, body: {}, headers: {})
15
+ handle_response client.connection.post(url, body, headers)
16
+ end
17
+
18
+ def handle_response(response)
19
+ case response.status
20
+ when 400
21
+ raise Error, "Your request was malformed. #{response.body['errorMessage']}"
22
+ when 401
23
+ raise Error, "You did not supply valid authentication credentials. #{response.body['errorMessage']}"
24
+ when 403
25
+ raise Error, "You are not allowed to perform that action. #{response.body['errorMessage']}"
26
+ when 404
27
+ raise Error, "No results were found for your request. #{response.body['errorMessage']}"
28
+ when 500
29
+ raise Error, "Something wrong happened. #{response.body['errorMessage']}"
30
+ end
31
+ response
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,23 @@
1
+ module Mpesa
2
+ class Status < Resource
3
+ PATH = 'mpesa/transactionstatus/v1/query'
4
+ def call
5
+ Object.new post_request(url: PATH, body: body).body
6
+ end
7
+
8
+ def body
9
+ {
10
+ 'CommandID': 'TransactionStatusQuery',
11
+ 'PartyA': params['shortcode'],
12
+ 'IdentifierType': 4,
13
+ 'Remarks': params['remarks'],
14
+ 'Initiator': params['initiator_username'],
15
+ 'SecurityCredential': '',
16
+ 'QueueTimeOutURL': params['timeout_url'],
17
+ 'ResultURL': params['result_url'],
18
+ 'TransactionID': params['transaction_id'],
19
+ 'Occassion': params['occasion']
20
+ }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ module Mpesa
2
+ class Payout < Resource
3
+ PATH = 'mpesa/b2c/v1/paymentrequest'.freeze
4
+
5
+ def call
6
+ Object.new post_request(url: PATH, body: body).body
7
+ end
8
+
9
+ def body
10
+ {
11
+ 'InitiatorName': args[:initiator_username],
12
+ 'SecurityCredential': credentials,
13
+ 'CommandID': args[:command_id],
14
+ 'Amount': args[:amount],
15
+ 'PartyA': client.shortcode || args[:shortcode],
16
+ 'PartyB': args[:phone],
17
+ 'Remarks': args[:remarks],
18
+ 'QueueTimeOutURL': args[:timeout_url],
19
+ 'ResultURL': args[:result_url],
20
+ 'Occasion': args[:occasion]
21
+ }
22
+ end
23
+
24
+ def credentials
25
+ SecurityCred.new(args[:initiator_password], client.env).password_credential
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ module Mpesa
2
+ class Register < Resource
3
+ PATH = 'mpesa/c2b/v1/registerurl'.freeze
4
+
5
+ def call
6
+ Object.new post_request(url: PATH, body: body).body
7
+ end
8
+
9
+ def body
10
+ {
11
+ 'ShortCode': args[:shortcode],
12
+ 'ResponseType': 'Completed',
13
+ 'ConfirmationURL': args[:confirmation_url],
14
+ 'ValidationURL': args[:validation_url]
15
+ }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module Mpesa
2
+ class Status < Resource
3
+ PATH = 'mpesa/transactionstatus/v1/query'
4
+ def call
5
+ Object.new post_request(url: PATH, body: body).body
6
+ end
7
+
8
+ def body
9
+ {
10
+
11
+ }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,35 @@
1
+ require 'base64'
2
+
3
+ module Mpesa
4
+ class Stk < Resource
5
+ PATH = 'mpesa/stkpush/v1/processrequest'
6
+
7
+ def call
8
+ Object.new post_request(url: PATH, body: body).body
9
+ end
10
+
11
+ def body
12
+ {
13
+ 'BusinessShortCode': args[:shortcode] || client.shortcode,
14
+ 'Password': password,
15
+ 'Timestamp': timestamp.to_s,
16
+ 'TransactionType': 'CustomerPayBillOnline',
17
+ 'Amount': args[:amount],
18
+ 'PartyA': args[:phone],
19
+ 'PartyB': args[:shortcode] || client.shortcode,
20
+ 'PhoneNumber': args[:phone],
21
+ 'CallBackURL': args[:callback_url],
22
+ 'AccountReference': args[:reference],
23
+ 'TransactionDesc': args[:trans_desc]
24
+ }
25
+ end
26
+
27
+ def password
28
+ Base64.strict_encode64("#{args[:shortcode]}#{client.pass_key || args[:pass_key]}#{timestamp}")
29
+ end
30
+
31
+ def timestamp
32
+ Time.now.strftime('%Y%m%d%H%M%S').to_i
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ module Mpesa
2
+ class Token < Resource
3
+ def token
4
+ Object.new get_request(url: 'oauth/v1/generate?grant_type=client_credentials', basic_auth: true).body
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+ require 'base64'
5
+
6
+ module Mpesa
7
+ # Security Credentials
8
+ class SecurityCred
9
+ attr_reader :initiator_password, :env
10
+
11
+ def initialize(pass, env)
12
+ @initiator_password = pass
13
+ @env = env
14
+ end
15
+
16
+ def password_credential
17
+ raw = if env == 'production'
18
+ File.read(File.join(File.dirname(__FILE__), '../cert/production.pem'))
19
+ else
20
+ File.read(File.join(File.dirname(__FILE__), '../cert/sandbox.pem'))
21
+ end
22
+
23
+ cert = OpenSSL::X509::Certificate.new(raw)
24
+ key = cert.public_key
25
+ Base64.strict_encode64(key.public_encrypt(initiator_password))
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module Mpesa
2
+ VERSION = '0.3.0'
3
+ end
data/lib/mpesa.rb ADDED
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'mpesa/version'
4
+
5
+ # main module
6
+ module Mpesa
7
+ autoload :Error, 'mpesa/error'
8
+ autoload :Client, 'mpesa/client'
9
+ autoload :Object, 'mpesa/object'
10
+ autoload :Resource, 'mpesa/resource'
11
+ autoload :SecurityCred, 'mpesa/securitycred'
12
+
13
+ autoload :Register, 'mpesa/resources/register'
14
+ autoload :Token, 'mpesa/resources/token'
15
+ autoload :Stk, 'mpesa/resources/stk'
16
+ autoload :Payout, 'mpesa/resources/payout'
17
+ autoload :Status, 'mpesa/resources/status'
18
+ autoload :Balance, 'mpesa/resources/balance'
19
+
20
+ autoload :Instance, 'mpesa/objects/instace'
21
+ end
data/mpesa.gemspec ADDED
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/mpesa/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'mpesarb'
7
+ spec.version = Mpesa::VERSION
8
+ spec.authors = ['Moses Gathuku']
9
+ spec.email = ['mosesgathuku95@gmail.com']
10
+
11
+ spec.summary = 'a simple gem to integrate ruby with mpesa Apis'
12
+ spec.description = 'the gem will allow you to simply integrate with mpesa apis'
13
+ spec.homepage = 'https://github.com/gathuku/ruby_mpesa'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
16
+
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['source_code_uri'] = 'https://github.com/gathuku/mpesa'
19
+ spec.metadata['changelog_uri'] = 'https://github.com/gathuku/mpesa'
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.bindir = 'exe'
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ['lib']
29
+
30
+ spec.add_development_dependency 'bundler', '>= 2.1.4'
31
+ spec.add_development_dependency 'rake', '>= 12.3'
32
+ # dependancies
33
+ spec.add_runtime_dependency 'faraday', '>= 1.1'
34
+ spec.add_runtime_dependency 'faraday_middleware', '~> 1.1'
35
+ spec.add_runtime_dependency 'openssl', '>= 2.1'
36
+ # request
37
+ spec.add_development_dependency 'minitest'
38
+ spec.add_development_dependency 'minitest-reporters'
39
+ spec.add_development_dependency 'vcr'
40
+ spec.add_development_dependency 'webmock', '~> 3.7'
41
+ # debugging
42
+ spec.add_development_dependency 'byebug'
43
+ spec.add_development_dependency 'pry-byebug'
44
+ # code coverage
45
+ spec.add_development_dependency 'coveralls'
46
+ end
metadata ADDED
@@ -0,0 +1,245 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mpesarb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Moses Gathuku
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-09-05 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: 2.1.4
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.1.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '12.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '12.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '1.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '1.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: faraday_middleware
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: openssl
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '2.1'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '2.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest-reporters
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: vcr
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: webmock
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.7'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.7'
139
+ - !ruby/object:Gem::Dependency
140
+ name: byebug
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: pry-byebug
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: coveralls
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ description: the gem will allow you to simply integrate with mpesa apis
182
+ email:
183
+ - mosesgathuku95@gmail.com
184
+ executables: []
185
+ extensions: []
186
+ extra_rdoc_files: []
187
+ files:
188
+ - ".github/workflows/mpesa.yml"
189
+ - ".gitignore"
190
+ - ".travis.yml"
191
+ - CHANGELOG.md
192
+ - CODE_OF_CONDUCT.md
193
+ - Dockerfile
194
+ - Gemfile
195
+ - Gemfile.lock
196
+ - LICENSE.txt
197
+ - README.md
198
+ - Rakefile
199
+ - bin/console
200
+ - bin/setup
201
+ - docker-compose.yml
202
+ - lib/cert/production.pem
203
+ - lib/cert/sandbox.pem
204
+ - lib/mpesa.rb
205
+ - lib/mpesa/client.rb
206
+ - lib/mpesa/error.rb
207
+ - lib/mpesa/object.rb
208
+ - lib/mpesa/objects/instace.rb
209
+ - lib/mpesa/resource.rb
210
+ - lib/mpesa/resources/balance.rb
211
+ - lib/mpesa/resources/payout.rb
212
+ - lib/mpesa/resources/register.rb
213
+ - lib/mpesa/resources/status.rb
214
+ - lib/mpesa/resources/stk.rb
215
+ - lib/mpesa/resources/token.rb
216
+ - lib/mpesa/securitycred.rb
217
+ - lib/mpesa/version.rb
218
+ - mpesa.gemspec
219
+ homepage: https://github.com/gathuku/ruby_mpesa
220
+ licenses:
221
+ - MIT
222
+ metadata:
223
+ homepage_uri: https://github.com/gathuku/ruby_mpesa
224
+ source_code_uri: https://github.com/gathuku/mpesa
225
+ changelog_uri: https://github.com/gathuku/mpesa
226
+ post_install_message:
227
+ rdoc_options: []
228
+ require_paths:
229
+ - lib
230
+ required_ruby_version: !ruby/object:Gem::Requirement
231
+ requirements:
232
+ - - ">="
233
+ - !ruby/object:Gem::Version
234
+ version: 2.3.0
235
+ required_rubygems_version: !ruby/object:Gem::Requirement
236
+ requirements:
237
+ - - ">="
238
+ - !ruby/object:Gem::Version
239
+ version: '0'
240
+ requirements: []
241
+ rubygems_version: 3.2.15
242
+ signing_key:
243
+ specification_version: 4
244
+ summary: a simple gem to integrate ruby with mpesa Apis
245
+ test_files: []