listo 0.1.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: 71fa066f9c0d4b8989daa59834aab045bb058876f9b1c729fc0ca9a9111f71ba
4
+ data.tar.gz: 41a1274e380080acb24a3a12b571e810e25578e034080efa1e21370a3bc30633
5
+ SHA512:
6
+ metadata.gz: ec9b96f1ff54f039070c40ed419dbea0b8affa60da5792585ed5897557342ab2d52e7869badc4db622cc8ab7a9d42a3590865d2f483180714f0c66699351d451
7
+ data.tar.gz: cbc4be2daa4f820ec1e6a778199d934a69134b4c1df339c5aa4b351b33f66fb6ddf822ef7a75d55a31018e3e730e51462bc7c15eaa1efccb055a65abe8f79912
data/.editorconfig ADDED
@@ -0,0 +1,11 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ trim_trailing_whitespace = true
7
+ insert_final_newline = false
8
+
9
+ [*.{rb,yml}]
10
+ indent_style = space
11
+ indent_size = 2
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.0
5
+ before_install: gem install bundler -v 1.16.1
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,58 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ listo (0.1.0)
5
+ faraday (~> 0.12.2)
6
+ faraday_middleware (~> 0.10.0)
7
+ openssl (~> 2.1, >= 2.1.1)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ addressable (2.5.2)
13
+ public_suffix (>= 2.0.2, < 4.0)
14
+ crack (0.4.3)
15
+ safe_yaml (~> 1.0.0)
16
+ diff-lcs (1.3)
17
+ faraday (0.12.2)
18
+ multipart-post (>= 1.2, < 3)
19
+ faraday_middleware (0.10.1)
20
+ faraday (>= 0.7.4, < 1.0)
21
+ hashdiff (0.3.7)
22
+ multipart-post (2.0.0)
23
+ openssl (2.1.1)
24
+ public_suffix (3.0.2)
25
+ rake (10.5.0)
26
+ rspec (3.7.0)
27
+ rspec-core (~> 3.7.0)
28
+ rspec-expectations (~> 3.7.0)
29
+ rspec-mocks (~> 3.7.0)
30
+ rspec-core (3.7.1)
31
+ rspec-support (~> 3.7.0)
32
+ rspec-expectations (3.7.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.7.0)
35
+ rspec-mocks (3.7.0)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.7.0)
38
+ rspec-support (3.7.1)
39
+ safe_yaml (1.0.4)
40
+ vcr (3.0.3)
41
+ webmock (2.3.2)
42
+ addressable (>= 2.3.6)
43
+ crack (>= 0.3.2)
44
+ hashdiff
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ bundler (~> 1.16)
51
+ listo!
52
+ rake (~> 10.0)
53
+ rspec (~> 3.0)
54
+ vcr (~> 3.0, >= 3.0.3)
55
+ webmock (~> 2.1)
56
+
57
+ BUNDLED WITH
58
+ 1.16.1
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # Listo
2
+
3
+ A Ruby client for the [listo.mx](https://listo.mx/) API.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'listo'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install listo
20
+
21
+ ## Usage
22
+
23
+ ### Client setup
24
+
25
+ ```Ruby
26
+ Listo::Client.configure do |client|
27
+ client.token = 'LISTO_API_TOKEN'
28
+ client.cert_file = './path/cert.cer'
29
+ client.pkey_file = './path/pkcs8.pem'
30
+ client.pkey_passphrase = 'passphrase'
31
+ client.debug_mode = false # default
32
+ end
33
+ ```
34
+
35
+ The PKEY is usually provided in a DER format, you can create a copy in a PEM format with the following command:
36
+
37
+ ```sh
38
+ openssl pkcs8 -inform DER -outform PEM -in pkcs8.key -out pkcs8.pem
39
+ ```
40
+
41
+ ### Invoicing
42
+
43
+ ##### Generate XML
44
+
45
+ ```Ruby
46
+ Listo::Invoicing.generate_xml(invoice_data)
47
+ ```
48
+
49
+ ##### Certify XML
50
+
51
+ ```Ruby
52
+ Listo::Invoicing.certify_xml(xml, original_chain, data)
53
+ ```
54
+
55
+ For more details checkout the listo.mx [api docs](https://apidocs.listo.mx).
56
+ ## Development
57
+
58
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
59
+
60
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
61
+
62
+ ## Contributing
63
+
64
+ Bug reports and pull requests are welcome on GitHub at https://github.com/aliada-mx/listo.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "listo"
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
+ require "irb"
14
+ 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,17 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ module Listo
5
+ class Certificate < SimpleDelegator
6
+ def initialize(cert_file)
7
+ cert_der = File.read(cert_file)
8
+ cert = OpenSSL::X509::Certificate.new(cert_der)
9
+
10
+ super(cert)
11
+ end
12
+
13
+ def to_der64
14
+ Base64.encode64(to_der)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,40 @@
1
+ require 'listo/connection'
2
+ require 'listo/invoicing'
3
+ require 'listo/certificate'
4
+ require 'listo/pkey'
5
+
6
+ module Listo
7
+ class Client
8
+ attr_reader :connection, :cert, :pkey
9
+
10
+ attr_accessor(
11
+ :token,
12
+ :cert_file,
13
+ :pkey_passphrase,
14
+ :pkey_file,
15
+ :debug_mode,
16
+ )
17
+
18
+ def self.current
19
+ @client
20
+ end
21
+
22
+ def self.configure(&config)
23
+ yield @client = new
24
+
25
+ @client
26
+ end
27
+
28
+ def cert
29
+ @cert ||= Listo::Certificate.new(cert_file)
30
+ end
31
+
32
+ def pkey
33
+ @pkey ||= Listo::PKey.new(pkey_file, pkey_passphrase)
34
+ end
35
+
36
+ def connection
37
+ Listo::Connection.new(token, debug_mode: debug_mode)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,32 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware'
3
+ require 'listo/middleware/raise_error'
4
+
5
+ module Listo
6
+ class Connection < SimpleDelegator
7
+ def initialize(token, debug_mode: false)
8
+ @debug_mode = debug_mode
9
+
10
+ connection = Faraday.new(url: url) do |faraday|
11
+ faraday.use Listo::Middleware::RaiseError
12
+
13
+ faraday.request :json
14
+ faraday.response :json, content_type: 'application/json'
15
+
16
+ faraday.adapter Faraday.default_adapter
17
+ end
18
+
19
+ connection.headers['Authorization'] = "Token #{token}"
20
+ connection.headers['Content-Type'] = 'application/json'
21
+ connection.headers['Accept'] = 'application/json'
22
+
23
+ super(connection)
24
+ end
25
+
26
+ private
27
+
28
+ def url
29
+ @debug_mode ? 'https://staging.listo.mx/api' : 'https://listo.mx/api'
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,21 @@
1
+ module Listo
2
+ module Error
3
+ class Error < StandardError
4
+ end
5
+
6
+ class ClientError < Error
7
+ attr_reader :status, :headers, :body
8
+
9
+ def initialize(env)
10
+ @status = env.dig(:status)
11
+ @headers = env.dig(:headers)
12
+ @body = env.dig(:body)
13
+
14
+ super("the server responded with status #{@status}")
15
+ end
16
+ end
17
+
18
+ class StampError < Error
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,56 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ module Listo
5
+ class Invoicing
6
+ class << self
7
+ extend Forwardable
8
+
9
+ def_delegators :client, :cert, :pkey
10
+
11
+ def generate_xml(params = [])
12
+ client.connection.post('invoicing/generate_xml', params).body
13
+ end
14
+
15
+ def certify_xml(xml, original_chain, data)
16
+ params = {
17
+ xml: xml,
18
+ certificate_num: certificate_num,
19
+ certificate: certificate,
20
+ signature: signature(original_chain),
21
+ data: data,
22
+ }
23
+
24
+ response = client.connection.post('invoicing/certify_xml', params).body
25
+
26
+ # warning: listo reponds stamp errors with HTTP 200
27
+ if response.dig('status') == 'error'
28
+ raise Listo::Error::StampError, response.dig('error_description')
29
+ end
30
+
31
+ response
32
+ end
33
+
34
+ private
35
+
36
+ def client
37
+ Listo::Client.current
38
+ end
39
+
40
+ def certificate
41
+ cert.to_der64.delete("\n")
42
+ end
43
+
44
+ def certificate_num
45
+ cert.serial.to_s(2)
46
+ end
47
+
48
+ def signature(original_chain)
49
+ original_chain.gsub!("|#{'0' * 20}|", "|#{certificate_num}|")
50
+ signature = pkey.sign(OpenSSL::Digest::SHA256.new, original_chain)
51
+
52
+ Base64.encode64(signature).delete("\n")
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,27 @@
1
+ require 'faraday'
2
+ require 'listo/error'
3
+
4
+ module Listo
5
+ module Middleware
6
+ class RaiseError < Faraday::Response::Middleware
7
+ ClientErrorStatuses = 400...600
8
+
9
+ def on_complete(env)
10
+ case env[:status]
11
+ when ClientErrorStatuses
12
+ raise Listo::Error::ClientError, response_values(env)
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def response_values(env)
19
+ {
20
+ status: env.status,
21
+ headers: env.response_headers,
22
+ body: env.body
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
data/lib/listo/pkey.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'openssl'
2
+
3
+ module Listo
4
+ class PKey < SimpleDelegator
5
+ def initialize(key_file, pass_phrase = nil)
6
+ key_pem = File.read(key_file)
7
+ key = OpenSSL::PKey::RSA.new(key_pem, pass_phrase)
8
+
9
+ super(key)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module Listo
2
+ VERSION = '0.1.0'
3
+ end
data/lib/listo.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'listo/client'
2
+ require 'listo/version'
3
+
4
+ module Listo
5
+ end
data/listo.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'listo/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'listo'
7
+ spec.version = Listo::VERSION
8
+ spec.authors = ['Luis Alfredo Lorenzo']
9
+ spec.email = ['babasbot@gmail.com']
10
+
11
+ spec.summary = 'A Ruby wrapper for the listo.mx API'
12
+ spec.description = 'A Ruby implementation for the listo.mx web API.'
13
+ spec.homepage = 'https://github.com/aliada-mx/listo'
14
+ spec.license = 'Nonstandard'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.16'
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
+ spec.add_development_dependency 'rspec', '~> 3.0'
26
+ spec.add_development_dependency 'vcr', '~> 3.0', '>= 3.0.3'
27
+
28
+ spec.add_development_dependency 'webmock', '~> 2.1'
29
+
30
+ spec.add_dependency 'faraday', '~> 0.12.2'
31
+ spec.add_dependency 'faraday_middleware', '~> 0.10.0'
32
+ spec.add_dependency 'openssl', '~> 2.1', '>= 2.1.1'
33
+ end
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: listo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Luis Alfredo Lorenzo
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-05-31 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.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: vcr
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 3.0.3
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '3.0'
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 3.0.3
75
+ - !ruby/object:Gem::Dependency
76
+ name: webmock
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '2.1'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '2.1'
89
+ - !ruby/object:Gem::Dependency
90
+ name: faraday
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: 0.12.2
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: 0.12.2
103
+ - !ruby/object:Gem::Dependency
104
+ name: faraday_middleware
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: 0.10.0
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: 0.10.0
117
+ - !ruby/object:Gem::Dependency
118
+ name: openssl
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '2.1'
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: 2.1.1
127
+ type: :runtime
128
+ prerelease: false
129
+ version_requirements: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - "~>"
132
+ - !ruby/object:Gem::Version
133
+ version: '2.1'
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: 2.1.1
137
+ description: A Ruby implementation for the listo.mx web API.
138
+ email:
139
+ - babasbot@gmail.com
140
+ executables: []
141
+ extensions: []
142
+ extra_rdoc_files: []
143
+ files:
144
+ - ".editorconfig"
145
+ - ".gitignore"
146
+ - ".rspec"
147
+ - ".travis.yml"
148
+ - Gemfile
149
+ - Gemfile.lock
150
+ - README.md
151
+ - Rakefile
152
+ - bin/console
153
+ - bin/setup
154
+ - lib/listo.rb
155
+ - lib/listo/certificate.rb
156
+ - lib/listo/client.rb
157
+ - lib/listo/connection.rb
158
+ - lib/listo/error.rb
159
+ - lib/listo/invoicing.rb
160
+ - lib/listo/middleware/raise_error.rb
161
+ - lib/listo/pkey.rb
162
+ - lib/listo/version.rb
163
+ - listo.gemspec
164
+ homepage: https://github.com/aliada-mx/listo
165
+ licenses:
166
+ - Nonstandard
167
+ metadata: {}
168
+ post_install_message:
169
+ rdoc_options: []
170
+ require_paths:
171
+ - lib
172
+ required_ruby_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ required_rubygems_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ requirements: []
183
+ rubyforge_project:
184
+ rubygems_version: 2.7.3
185
+ signing_key:
186
+ specification_version: 4
187
+ summary: A Ruby wrapper for the listo.mx API
188
+ test_files: []