varanus 0.8.0 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c5717bc294e05caa49007dbf36c638ecf3a1d3e192aee421e51a73fec58246c
4
- data.tar.gz: 54f6feea0b5b692d415dd2f9d5eff9d0d088f29e26d54a700467494f11904048
3
+ metadata.gz: 60230826037fe526c9ea6086ccef657896d0df0344377d31fb58e966f19b8f2f
4
+ data.tar.gz: 72ced55d6a53f8cd61c01a13cea9c65da882ecb9ad0d314882af1633df36def4
5
5
  SHA512:
6
- metadata.gz: 246eeabfd08d59b01f5b8e6cca4d5ec8b4c7a73223ee34d8ac86a1d459d286fdf965ed410a381b2312ab72e97f3c0b65dc0da77c8b31776e53253f10b9003a05
7
- data.tar.gz: cdf0e60e8894b50e55f81901f0d441a7a3edf376856de12ea4a0bfc845267c3026926dcafabec14e7aebaf1292a25e6c8c0e76cbdfd9f346a9b18a3828021543
6
+ metadata.gz: ce123c1c9d05bff2aa0d829cc4d04c682872e8e8da28f6362fa8164b3fe397f2f3f5245a28b28f9979f79465916e6133215088289f4aaddf3d34978a976a9274
7
+ data.tar.gz: 3436eb567954074d1e4acc8ccd0bec419c279a411e56fddaf558d4384ff30fecfc7303470f7c95b79f32b445aab0526eaf386f294154b4ea4eea36563096287f
data/.codeclimate.yml ADDED
@@ -0,0 +1,4 @@
1
+ plugins:
2
+ rubocop:
3
+ enabled: true
4
+ channel: rubocop-0-59
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /test.rb
data/.rubocop.yml ADDED
@@ -0,0 +1,51 @@
1
+ AllCops:
2
+ NewCops: disable
3
+ TargetRubyVersion: 2.5
4
+
5
+ Bundler/OrderedGems:
6
+ AutoCorrect: false
7
+
8
+ Layout/LineLength:
9
+ Max: 90
10
+ Exclude:
11
+ - 'test/**/*'
12
+
13
+ Metrics/AbcSize:
14
+ Max: 25
15
+ Exclude:
16
+ - 'test/**/*'
17
+
18
+ Metrics/ClassLength:
19
+ Max: 125
20
+ Exclude:
21
+ - 'test/**/*'
22
+
23
+ Metrics/MethodLength:
24
+ Max: 20
25
+ Exclude:
26
+ - 'test/**/*'
27
+
28
+ Naming/FileName:
29
+ Exclude:
30
+ - Gemfile
31
+
32
+ Style/ClassAndModuleChildren:
33
+ EnforcedStyle: compact
34
+
35
+ Style/ConditionalAssignment:
36
+ Enabled: false
37
+
38
+ Style/MethodDefParentheses:
39
+ EnforcedStyle: require_no_parentheses_except_multiline
40
+
41
+ Style/NumericPredicate:
42
+ EnforcedStyle: comparison
43
+
44
+ Style/RescueModifier:
45
+ AutoCorrect: false
46
+
47
+ Style/SymbolArray:
48
+ EnforcedStyle: brackets
49
+
50
+ Style/WordArray:
51
+ EnforcedStyle: brackets
data/.travis.yml ADDED
@@ -0,0 +1,18 @@
1
+ ---
2
+ env:
3
+ global:
4
+ - CC_TEST_REPORTER_ID=11ec0aee76479858801566bb43fd7d76eced4cbb2432bcead71db59dae21eaae
5
+ sudo: false
6
+ language: ruby
7
+ cache: bundler
8
+ rvm:
9
+ - 2.5
10
+ - 2.6
11
+ - 2.7
12
+ before_install: gem install bundler -v 1.16.5
13
+ before_script:
14
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
15
+ - chmod +x ./cc-test-reporter
16
+ - ./cc-test-reporter before-build
17
+ after_script:
18
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
data/CHANGELOG.md ADDED
@@ -0,0 +1,48 @@
1
+ ### Version 0.9.0 (2026-02-16)
2
+ * Use faraday 2.x
3
+
4
+ ### Version 0.8.1 (2024-09-27)
5
+ * Fix gem build issues
6
+
7
+ ### Version 0.8.0 (2024-09-27)
8
+ * Varanus::SSL::CSR - improve support for subclassing
9
+ * Varanus::SSL::CSR.generate - support an EC key being passed in
10
+
11
+ ### Version 0.7.1 (2022-01-31)
12
+ * Varanus::SSL#certificate_types_standard - also exclude 'Extended Validation'
13
+
14
+ ### Version 0.7.0 (2020-02-03)
15
+ * Add Varanus::Domain#report
16
+
17
+ ### Version 0.6.0 (2020-02-01)
18
+ * Add Varanus::SSL#report
19
+ * Varanus::Reports (Varanus#reports) is now deprecated.
20
+
21
+ ### Version 0.5.1 (2021-01-28)
22
+ * Varanus::SSL::CSR - support EC certs
23
+
24
+ ### Version 0.5.0 (2021-01-26)
25
+ * Add Varanus::Domain
26
+ * Add Varanus::SSL#list and Varanus::SSL#info
27
+ * Add Varanus::Organization
28
+
29
+ ### 0.4.0 (2021-01-06)
30
+ * Add Varanus::DCV
31
+
32
+ ### 0.3.1 (2020-10-14)
33
+ * Fix issue when Sectigo reports two identical 'Short Life' certs
34
+
35
+ ### 0.3.0 (2020-08-24)
36
+ * Add support for new 'Short Life' certs
37
+
38
+ ### 0.2.1 (2018-11-13)
39
+ * Increase timeout value for SSL requests
40
+
41
+ ### 0.2.0 (2018-11-09)
42
+ * Added Varanus::SSL::CSR.generate
43
+ * Added Reports
44
+ * Varanus::Reports#ssl - list of SSL/TLS certs
45
+ * Varanus::Reports#domains - list of domains validated with DCV
46
+
47
+ ### 0.1.0 (2018-11-07)
48
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in varanus.gemspec
8
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,141 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ varanus (0.9.0)
5
+ faraday (~> 2.0)
6
+ savon (~> 2.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ addressable (2.8.7)
12
+ public_suffix (>= 2.0.2, < 7.0)
13
+ akami (1.3.3)
14
+ base64
15
+ gyoku (>= 0.4.0)
16
+ nokogiri
17
+ ast (2.4.2)
18
+ base64 (0.2.0)
19
+ bigdecimal (3.1.8)
20
+ builder (3.3.0)
21
+ crack (1.0.0)
22
+ bigdecimal
23
+ rexml
24
+ date (3.3.4)
25
+ docile (1.4.1)
26
+ faraday (2.14.1)
27
+ faraday-net_http (>= 2.0, < 3.5)
28
+ json
29
+ logger
30
+ faraday-net_http (3.4.2)
31
+ net-http (~> 0.5)
32
+ gyoku (1.4.0)
33
+ builder (>= 2.1.2)
34
+ rexml (~> 3.0)
35
+ hashdiff (1.1.1)
36
+ httpi (4.0.4)
37
+ base64
38
+ mutex_m
39
+ nkf
40
+ rack (>= 2.0, < 4)
41
+ json (2.7.2)
42
+ language_server-protocol (3.17.0.3)
43
+ logger (1.7.0)
44
+ mail (2.8.1)
45
+ mini_mime (>= 0.1.1)
46
+ net-imap
47
+ net-pop
48
+ net-smtp
49
+ mini_mime (1.1.5)
50
+ minitest (5.25.1)
51
+ minitest-rg (5.3.0)
52
+ minitest (~> 5.0)
53
+ mocha (2.4.5)
54
+ ruby2_keywords (>= 0.0.5)
55
+ mutex_m (0.2.0)
56
+ net-http (0.9.1)
57
+ uri (>= 0.11.1)
58
+ net-imap (0.4.16)
59
+ date
60
+ net-protocol
61
+ net-pop (0.1.2)
62
+ net-protocol
63
+ net-protocol (0.2.2)
64
+ timeout
65
+ net-smtp (0.5.0)
66
+ net-protocol
67
+ nkf (0.2.0)
68
+ nokogiri (1.16.7-x86_64-linux)
69
+ racc (~> 1.4)
70
+ nori (2.7.1)
71
+ bigdecimal
72
+ parallel (1.26.3)
73
+ parser (3.3.5.0)
74
+ ast (~> 2.4.1)
75
+ racc
76
+ public_suffix (6.0.1)
77
+ racc (1.8.1)
78
+ rack (3.1.7)
79
+ rainbow (3.1.1)
80
+ rake (10.5.0)
81
+ regexp_parser (2.9.2)
82
+ rexml (3.3.7)
83
+ rubocop (1.66.1)
84
+ json (~> 2.3)
85
+ language_server-protocol (>= 3.17.0)
86
+ parallel (~> 1.10)
87
+ parser (>= 3.3.0.2)
88
+ rainbow (>= 2.2.2, < 4.0)
89
+ regexp_parser (>= 2.4, < 3.0)
90
+ rubocop-ast (>= 1.32.2, < 2.0)
91
+ ruby-progressbar (~> 1.7)
92
+ unicode-display_width (>= 2.4.0, < 3.0)
93
+ rubocop-ast (1.32.3)
94
+ parser (>= 3.3.1.0)
95
+ ruby-progressbar (1.13.0)
96
+ ruby2_keywords (0.0.5)
97
+ savon (2.15.1)
98
+ akami (~> 1.2)
99
+ builder (>= 2.1.2)
100
+ gyoku (~> 1.2)
101
+ httpi (>= 4, < 5)
102
+ mail (~> 2.5)
103
+ nokogiri (>= 1.8.1)
104
+ nori (~> 2.4)
105
+ wasabi (>= 3.7, < 6)
106
+ simplecov (0.22.0)
107
+ docile (~> 1.1)
108
+ simplecov-html (~> 0.11)
109
+ simplecov_json_formatter (~> 0.1)
110
+ simplecov-html (0.13.1)
111
+ simplecov_json_formatter (0.1.4)
112
+ timeout (0.4.1)
113
+ unicode-display_width (2.6.0)
114
+ uri (1.1.1)
115
+ wasabi (5.0.3)
116
+ addressable
117
+ faraday (>= 1.9, < 3)
118
+ nokogiri (>= 1.13.9)
119
+ webmock (3.23.1)
120
+ addressable (>= 2.8.0)
121
+ crack (>= 0.3.2)
122
+ hashdiff (>= 0.4.0, < 2.0.0)
123
+ yard (0.9.37)
124
+
125
+ PLATFORMS
126
+ x86_64-linux
127
+
128
+ DEPENDENCIES
129
+ bundler (~> 2.0)
130
+ minitest (~> 5.0)
131
+ minitest-rg
132
+ mocha
133
+ rake (~> 10.0)
134
+ rubocop
135
+ simplecov
136
+ varanus!
137
+ webmock
138
+ yard
139
+
140
+ BUNDLED WITH
141
+ 2.3.27
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Duke University
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,104 @@
1
+ # Varanus
2
+
3
+ This gem provides an interface to Sectigo's (formerly Comodo CA) APIs for working
4
+ with SSL/TLS certificates as well as its reporting API.
5
+
6
+ Support for Sectigo's other APIs (S/MIME, code signing, device certificates, etc) may
7
+ be added at a later date. Merge requests to add some of this functionality would be
8
+ greatly appreciated.
9
+
10
+ [![Build Status](https://travis-ci.org/duke-automation/varanus.svg?branch=master)](https://travis-ci.org/duke-automation/varanus)
11
+ [![Gem Version](https://badge.fury.io/rb/varanus.svg)](http://badge.fury.io/rb/varanus)
12
+ [![Maintainability](https://api.codeclimate.com/v1/badges/593ef1aa2ba757b5374f/maintainability)](https://codeclimate.com/github/duke-automation/varanus/maintainability)
13
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/593ef1aa2ba757b5374f/test_coverage)](https://codeclimate.com/github/duke-automation/varanus/test_coverage)
14
+
15
+ ## Usage
16
+
17
+ #### Generate and sign SSL cert
18
+
19
+ ```ruby
20
+ key, csr = Varanus::SSL::CSR.generate(['example.com'])
21
+ varanus = Varanus.new(customer_uri, username, password)
22
+ id = varanus.ssl.sign csr, org_id
23
+ begin
24
+ cert = varanus.ssl.collect id
25
+ rescue Varanus::Error::StillProcessing
26
+ sleep 1
27
+ retry
28
+ end
29
+ puts key
30
+ puts cert
31
+ ```
32
+
33
+ #### Sign SSL cert from CSR
34
+
35
+ ```ruby
36
+ csr = File.read('/path/to/file.csr')
37
+ varanus = Varanus.new(customer_uri, username, password)
38
+ id = varanus.ssl.sign csr, org_id
39
+ begin
40
+ cert = varanus.ssl.collect id
41
+ rescue Varanus::Error::StillProcessing
42
+ sleep 1
43
+ retry
44
+ end
45
+ puts cert
46
+ ```
47
+
48
+ #### Revoke SSL cert
49
+
50
+ ```ruby
51
+ Varanus.new(customer_uri, username, password).ssl.revoke(id)
52
+ ```
53
+
54
+ #### Reports
55
+
56
+ Report on all SSL certs
57
+ ```ruby
58
+ pp Varanus.new(customer_uri, usernams, password).reports.ssl
59
+ ```
60
+
61
+ Report on all domains (DCV status)
62
+ ```ruby
63
+ pp Varanus.new(customer_uri, usernams, password).reports.domains
64
+ ```
65
+
66
+ #### Authentication
67
+
68
+ Authentication requires the same credentials you use to login to cert-manager.com as well as the ```customer_uri```. If your URL to log into cert-manager.com is https://cert-manager.com/customer/MyCompany then your ```customer_uri``` will be ```'MyCompany'```
69
+
70
+ #### Finding Organization Id (org_id)
71
+
72
+ Signing a cert requires specifying an ```org_id```. Each department in cert-manager.com has an associated ```org_id```.
73
+
74
+ To find the ```org_id```, log into cert-manager.com, go to **Settings** -> **Departments**, then click to edit the department you are interested in. The value you want is in the **OrgID** field.
75
+
76
+ ## Installation
77
+
78
+ Add this line to your application's Gemfile:
79
+
80
+ ```ruby
81
+ gem 'varanus'
82
+ ```
83
+
84
+ And then execute:
85
+
86
+ $ bundle
87
+
88
+ Or install it yourself as:
89
+
90
+ $ gem install varanus
91
+
92
+ ## Development
93
+
94
+ 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.
95
+
96
+ 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).
97
+
98
+ ## Contributing
99
+
100
+ Bug reports and pull requests are welcome on GitHub at https://github.com/duke-automation/varanus.
101
+
102
+ ## License
103
+
104
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
10
+ end
11
+
12
+ task default: :test
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'varanus'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ 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,11 @@
1
+ version: '3'
2
+ services:
3
+ console:
4
+ image: ruby:3.1
5
+ volumes:
6
+ - .:/app:z
7
+ hostname: varanus-dev
8
+ working_dir: /app
9
+ stdin_open: true
10
+ tty: true
11
+ command: bash -c './bin/setup && ./bin/console'
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # An connection to the DCV API. This should not be initialized directly. Instead,
4
+ # use Varanus#dcv
5
+ class Varanus::DCV < Varanus::RestResource
6
+ # Returns an Array of DCV information about searched for domains.
7
+ # This method will automatically page through all results
8
+ # @param opts [Hash] - all opts are optional
9
+ # @option opts [String] :domain Domain to search for
10
+ # @option opts [Integer] :org ID of organization
11
+ # @option opts [Integer] :department ID of department
12
+ # @option opts [String] :dcvStatus
13
+ # @option opts [String] :orderStatus
14
+ # @option opts [Integer] :expiresIn Expires in (days)
15
+ #
16
+ # Results will included an extra 'expiration_date_obj' if 'expirationDate' is in the
17
+ # response
18
+ def search opts = {}
19
+ get_with_size_and_position('dcv/v2/validation', opts).map(&method(:_format_status))
20
+ end
21
+
22
+ # Start domain validation process. This must be called before #submit is called
23
+ # @option domain [String] domain to validate
24
+ # @option type [String] Type of validation. Must be one of 'http', 'https', 'cname',
25
+ # or 'email'
26
+ def start domain, type
27
+ post("dcv/v1/validation/start/domain/#{type}", domain: domain)
28
+ end
29
+
30
+ # Retrieve DCV status for a single domain
31
+ # Result will included an extra 'expiration_date_obj' if 'expirationDate' is in the
32
+ # response
33
+ def status domain
34
+ _format_status(post('dcv/v2/validation/status', domain: domain))
35
+ end
36
+
37
+ # Submit domain validation for verficiation. This must be called after #start
38
+ # @option domain [String] domain to validate
39
+ # @option type [String] Type of validation. Must be one of 'http', 'https', 'cname',
40
+ # or 'email'
41
+ # @option email_address [String] This is required of +type+ is 'email'. Otherwise, it is
42
+ # ignored.
43
+ def submit domain, type, email_address = nil
44
+ if type.to_s == 'email'
45
+ raise ArgumentError, 'email_address must be specified' if email_address.nil?
46
+
47
+ post('dcv/v1/validation/submit/domain/email', domain: domain,
48
+ email: email_address)
49
+ else
50
+ post("dcv/v1/validation/submit/domain/#{type}", domain: domain)
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def _format_status status
57
+ return status unless status['expirationDate']
58
+
59
+ status.merge('expiration_date_obj' =>
60
+ Date.strptime(status['expirationDate'], '%Y-%m-%d'))
61
+ end
62
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A connection to the Domain API
4
+ class Varanus::Domain < Varanus::RestResource
5
+ # Create a new domain. The domain may need to be manually approved after this is
6
+ # called.
7
+ # +name+ is the domain
8
+ # +delegations+ is an Array of Hashes. Each Hash should have an 'orgId' and
9
+ # 'certTypes' key
10
+ # opts may include the following keys:
11
+ # - :description - optional - String
12
+ # - :active - optional - Boolean (defaults to +true+)
13
+ # - :allow_subdomains - optional - set to +false+ if you don't want to allow sub
14
+ # domains for this entry
15
+ #
16
+ # @returns [String] - URL for newly created domain
17
+ def create domain, delegations, opts = {}
18
+ opts = opts.dup
19
+ allow_subdomains = opts.delete(:allow_subdomains)
20
+ domain = "*.#{domain}" if allow_subdomains != false && !domain.start_with?('*.')
21
+
22
+ result = @varanus.connection.post('domain/v1',
23
+ opts.merge(name: domain, delegations: delegations))
24
+ check_result result
25
+ result.headers['Location']
26
+ end
27
+
28
+ # Return info on domain. +id+ must be the id returned by #list
29
+ def info id
30
+ get("domain/v1/#{id}")
31
+ end
32
+
33
+ def list opts = {}
34
+ get_with_size_and_position('domain/v1', opts)
35
+ end
36
+
37
+ def list_with_info opts = {}
38
+ domains = list(opts)
39
+ domains.map! { |domain| info(domain['id']) }
40
+ domains
41
+ end
42
+
43
+ def report
44
+ post('report/v1/domains', {})['reports']
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Error returned from the Sectigo API
4
+ class Varanus::Error < StandardError
5
+ # @return [Integer] Code associated with error
6
+ attr_reader :code
7
+
8
+ def initialize code, msg
9
+ @code = code
10
+ super(msg)
11
+ end
12
+ end
13
+
14
+ # Certificate is still being signed.
15
+ class Varanus::Error::StillProcessing < Varanus::Error; end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A connection to the Organization API
4
+ class Varanus::Organization < Varanus::RestResource
5
+ # Return info on organization.
6
+ def info id
7
+ get("organization/v1/#{id}")
8
+ end
9
+
10
+ def list
11
+ get('organization/v1')
12
+ end
13
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ # An connection to the Reports API. This should not be initialized directly. Instead,
4
+ # use Varanus#reports
5
+ class Varanus::Reports
6
+ SSL_CERT_STATUSES = {
7
+ any: 0,
8
+ requested: 1,
9
+ downloaded: 2,
10
+ revoked: 3,
11
+ expired: 4,
12
+ pending_download: 5,
13
+ not_enrolled: 6
14
+ }.freeze
15
+
16
+ # @note Do not call this directly. Use {Varanus#reports} to initialize
17
+ def initialize varanus
18
+ @varanus = varanus
19
+ end
20
+
21
+ # DEPRECATED: Please use Varanus::Domain#list_with_info instead.
22
+ def domains
23
+ warn 'DEPRECATION WARNING: Varanus::Reports#domains is deprecated. ' \
24
+ 'Use Varanus::Domain#report instead'
25
+ r = soap_call :get_domain_report, {}
26
+ format_results r[:report_row_domains]
27
+ end
28
+
29
+ # DEPRECATED: Please use Varanus::SSL#report instead.
30
+ def ssl opts = {}
31
+ warn 'DEPRECATION WARNING: Varanus::Reports#ssl is deprecated. ' \
32
+ 'Use Varanus::SSL#report instead'
33
+
34
+ msg = { organizationNames: nil, certificateStatus: 0 }
35
+
36
+ msg[:organizationNames] = Array(opts[:orgs]).join(',') if opts.include? :orgs
37
+ if opts.include? :status
38
+ msg[:certificateStatus] = SSL_CERT_STATUSES[opts[:status]]
39
+ raise ArgumentError, 'Invalid status' if msg[:certificateStatus].nil?
40
+ end
41
+
42
+ r = soap_call :get_SSL_report, msg
43
+ format_results r[:reports]
44
+ end
45
+
46
+ private
47
+
48
+ def format_results results
49
+ if results.is_a? Hash
50
+ [results]
51
+ else
52
+ results.to_a
53
+ end
54
+ end
55
+
56
+ def savon
57
+ @savon ||= Savon.client(
58
+ namespace: 'http://report.ws.epki.comodo.com/',
59
+ endpoint: 'https://cert-manager.com:443/ws/ReportService',
60
+ log: false
61
+ )
62
+ end
63
+
64
+ def soap_call func, opts = {}
65
+ msg = opts.dup
66
+ msg[:authData] = { customerLoginUri: @varanus.customer_uri, login: @varanus.username,
67
+ password: @varanus.password }
68
+
69
+ result = savon.call func, message: msg
70
+ result.body[(func.to_s.downcase + '_response').to_sym][:return]
71
+ end
72
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ # An abstract class for rest resources
4
+ # Rest resources should not be initialized directly. They should be created by methods
5
+ # on Varanus
6
+ class Varanus::RestResource
7
+ # :nodoc:
8
+ def initialize varanus
9
+ @varanus = varanus
10
+ end
11
+
12
+ private
13
+
14
+ def check_result result
15
+ body = result.body
16
+ return unless body.is_a?(Hash)
17
+ return if body['code'].nil?
18
+
19
+ klass = Varanus::Error
20
+ if body['code'] == 0 && body['description'] =~ /process/
21
+ klass = Varanus::Error::StillProcessing
22
+ end
23
+
24
+ raise klass.new(body['code'], body['description'])
25
+ end
26
+
27
+ def get path, *args
28
+ result = @varanus.connection.get(path, *args)
29
+ check_result result
30
+ result.body
31
+ end
32
+
33
+ # Performs multiple GETs with varying positions to ensure all results are returned.
34
+ def get_with_size_and_position path, opts = {}
35
+ size = opts[:size] || 200
36
+ position = opts[:position] || 0
37
+
38
+ results = []
39
+ loop do
40
+ params = { size: size, position: position }.merge(opts)
41
+ new_results = get(path, params)
42
+ results += new_results
43
+ break if new_results.length < size
44
+
45
+ position += size
46
+ end
47
+
48
+ results
49
+ end
50
+
51
+ def post path, *args
52
+ result = @varanus.connection.post(path, *args)
53
+ check_result result
54
+ result.body
55
+ end
56
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Wrapper class around a OpenSSL::X509::Request
4
+ # Provides helper functions to make reading information from the CSR easier
5
+ class Varanus::SSL::CSR
6
+ # Key size used when calling {.generate}
7
+ DEFAULT_KEY_SIZE = 4096
8
+
9
+ # Generate a CSR
10
+ # @param names [Array<String>] List of DNS names. The first one will be the CN
11
+ # @param key [OpenSSL::PKey::RSA, OpenSSL::PKey::DSA, nil] Secret key for the cert.
12
+ # A DSA key will be generated if +nil+ is passed in.
13
+ # @param subject [Hash] Options for the subject of the cert. By default only CN will
14
+ # be set
15
+ # @return [Array(OpenSSL::PKey::PKey, Varanus::SSL::CSR)] The private key for the cert
16
+ # and CSR
17
+ def self.generate names, key = nil, subject = {}
18
+ raise ArgumentError, 'names cannot be empty' if names.empty?
19
+
20
+ subject = subject.dup
21
+ subject['CN'] = names.first
22
+
23
+ key ||= OpenSSL::PKey::DSA.new(DEFAULT_KEY_SIZE)
24
+
25
+ request = OpenSSL::X509::Request.new
26
+ request.version = 0
27
+ request.subject = OpenSSL::X509::Name.parse subject.map { |k, v| "/#{k}=#{v}" }.join
28
+ request.add_attribute names_to_san_attribute(names)
29
+ if key.is_a? OpenSSL::PKey::EC
30
+ request.public_key = key
31
+ else
32
+ request.public_key = key.public_key
33
+ end
34
+
35
+ request.sign(key, OpenSSL::Digest.new('SHA256'))
36
+
37
+ [key, new(request)]
38
+ end
39
+
40
+ # :nodoc:
41
+ # Create a Subject Alternate Names attribute from an Array of dns names
42
+ def self.names_to_san_attribute names
43
+ ef = OpenSSL::X509::ExtensionFactory.new
44
+ name_str = names.map { |n| "DNS:#{n}" }.join(', ')
45
+ ext = ef.create_extension('subjectAltName', name_str, false)
46
+ seq = OpenSSL::ASN1::Sequence([ext])
47
+ ext_req = OpenSSL::ASN1::Set([seq])
48
+ OpenSSL::X509::Attribute.new('extReq', ext_req)
49
+ end
50
+
51
+ # Common Name (CN) for cert.
52
+ # @return [String]
53
+ attr_reader :cn
54
+
55
+ # OpenSSL::X509::Request representation of CSR
56
+ # @return [OpenSSL::X509::Request]
57
+ attr_reader :request
58
+
59
+ # @param csr [String, OpenSSL::X509::Request]
60
+ def initialize csr
61
+ if csr.is_a? OpenSSL::X509::Request
62
+ @request = csr
63
+ @text = csr.to_s
64
+ else
65
+ @text = csr.to_s
66
+ @request = OpenSSL::X509::Request.new @text
67
+ end
68
+
69
+ raise 'Improperly signed CSR' unless @request.verify @request.public_key
70
+
71
+ cn_ref = @request.subject.to_a.find { |a| a[0] == 'CN' }
72
+ @cn = cn_ref && cn_ref[1].downcase
73
+
74
+ _parse_sans
75
+
76
+ # If we have no CN or SAN, raise an error
77
+ raise 'CSR must have a CN and/or subjectAltName' if @cn.nil? && @sans.empty?
78
+ end
79
+
80
+ # Unique list of all DNS names for cert (CN and subject alt names)
81
+ # @return [Array<String>]
82
+ def all_names
83
+ ([@cn] + @sans).compact.uniq
84
+ end
85
+
86
+ # Key size for the cert
87
+ # @return [Integer]
88
+ def key_size
89
+ case @request.public_key
90
+ when OpenSSL::PKey::RSA
91
+ @request.public_key.n.num_bytes * 8
92
+ when OpenSSL::PKey::DSA
93
+ @request.public_key.p.num_bytes * 8
94
+ when OpenSSL::PKey::EC
95
+ @request.public_key.group.degree
96
+ else
97
+ raise "Unknown public key type: #{@request.public_key.class}"
98
+ end
99
+ end
100
+
101
+ # PEM format for cert
102
+ def to_s
103
+ @text
104
+ end
105
+
106
+ # DNS subject alt names
107
+ # @return [Array<String>]
108
+ def subject_alt_names
109
+ @sans
110
+ end
111
+
112
+ private
113
+
114
+ def _parse_sans
115
+ extensions = @request.attributes.select { |at| at.oid == 'extReq' }
116
+ sans_extensions = extensions.flat_map do |extension|
117
+ extension.value.value[0].value
118
+ .select { |ext| ext.first.value == 'subjectAltName' }
119
+ .map { |ext| ext.value.last }
120
+ end
121
+ @sans = sans_extensions.compact.flat_map do |san|
122
+ _parse_sans_extension san
123
+ end
124
+ end
125
+
126
+ def _parse_sans_extension ext
127
+ OpenSSL::ASN1.decode(ext.value).map do |s_entry|
128
+ unless s_entry.tag == 2 && s_entry.tag_class == :CONTEXT_SPECIFIC
129
+ raise "unknown tag #{s_entry.tag}"
130
+ end
131
+
132
+ s_entry.value.downcase
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ # An connection to the SSL/TSL API. This should not be initialized directly. Instead,
4
+ # use Varanus#ssl
5
+ class Varanus::SSL < Varanus::RestResource
6
+ # rubocop:disable Style/MutableConstant
7
+ # These constants are frozen, rubocop is failing to detect the freeze.
8
+ # See https://github.com/rubocop-hq/rubocop/issues/4406
9
+ REPORT_CERT_STATUS = { any: 0, requested: 1, issued: 2, revoked: 3, expired: 4 }
10
+ REPORT_CERT_STATUS.default_proc = proc { |_h, k|
11
+ raise ArgumentError, "Unknown certificateStatus: #{k.inspect}"
12
+ }
13
+ REPORT_CERT_STATUS.freeze
14
+
15
+ REPORT_CERT_DATE_ATTR = { revocation_date: 2, expiration_date: 3, request_date: 4,
16
+ issue_date: 5 }
17
+ REPORT_CERT_DATE_ATTR.default_proc = proc { |_h, k|
18
+ raise ArgumentError, "Unknown certificateDateAttribute: #{k.inspect}"
19
+ }
20
+ REPORT_CERT_DATE_ATTR.freeze
21
+ # rubocop:enable Style/MutableConstant
22
+
23
+ # Returns the option from #certificate_types that best matches the csr.
24
+ # @param csr [Varanus::SSL::CSR]
25
+ # @return [Hash] The option from {#certificate_types} that best matches the csr
26
+ def certificate_type_from_csr csr, days = nil
27
+ types = certificate_types_standard(days)
28
+ return types.first if types.length <= 1
29
+
30
+ regexp = cert_type_regexp(csr)
31
+ typ = types.find { |ct| ct['name'] =~ regexp } if regexp
32
+ return typ unless typ.nil?
33
+
34
+ types.find do |ct|
35
+ ct['name'] =~ /\bSSL\b/ && ct['name'] !~ /(?:Multi.?Domain|Wildcard)/i
36
+ end
37
+ end
38
+
39
+ # Certificate types that can be used to sign a cert
40
+ # @return [Array<Hash>]
41
+ def certificate_types
42
+ @certificate_types ||= get('ssl/v1/types')
43
+ end
44
+
45
+ # Return Array of certificate types based on standard sorting.
46
+ # @param days [Integer] if present, only include types that support the given day count
47
+ # @return [Array<Hash>]
48
+ def certificate_types_standard days = nil
49
+ types = certificate_types.reject do |ct|
50
+ ct['name'] =~ /\b(?:EV|Extended Validation|ECC|AMT|Elite)\b/
51
+ end
52
+ types = types.select! { |t| t['terms'].include? days } unless days.nil?
53
+
54
+ types
55
+ end
56
+
57
+ # Retrieves the cert.
58
+ # @param id [Integer] As returned by {#sign}
59
+ # @param type [String]
60
+ #
61
+ # +type+ can be one of:
62
+ # 'x509' - X509 format - cert and chain (default)
63
+ # 'x509CO' - X509 format - cert only
64
+ # 'x509IO' - X509 format - intermediates/root only
65
+ # 'x590IOR' - X509 format - intermediates/root only reversed
66
+ # 'base64' - PKCS#7 base64 encoded
67
+ # 'bin' - PKCS#7 bin encoded
68
+ #
69
+ # @raise [Varanus::Error::StillProcessing] Cert is still being signed
70
+ # @return [String] Certificate
71
+ def collect id, type = 'x509'
72
+ get("ssl/v1/collect/#{id}/#{type}")
73
+ end
74
+
75
+ # Returns info on the SSL certificate of the given name
76
+ def info id
77
+ get("ssl/v1/#{id}")
78
+ end
79
+
80
+ # List certs ids and serial numbers
81
+ def list opts = {}
82
+ get_with_size_and_position('ssl/v1', opts)
83
+ end
84
+
85
+ # Return a report (list) of SSL certs based on the options.
86
+ # The report includes a full set of details about the certs, not just the id/cn/serial
87
+ # +opts+ can include:
88
+ # (all are optional)
89
+ # - :organizationIds - Array - ids of organization/departments to include certs for
90
+ # - :certificateStatus - :any, :requested, :issued, :revoked, or :expired
91
+ # - :certificateDateAttribute - Specifies what fields :from and/or :to refer to.
92
+ # Can be: :revocation_date, :expiration_date,
93
+ # :request_date, or :issue_date
94
+ # - :from - Date - based on :certificateDateAttribute
95
+ # - :to - Date - based on :certificateDateAttribute
96
+ def report opts = { certificateStatus: :any }
97
+ # Default is to request any certificate status since the API call will fail if no
98
+ # options are passed
99
+ opts = { certificateStatus: :any } if opts.empty?
100
+ opts = _parse_report_opts(opts)
101
+
102
+ post('report/v1/ssl-certificates', opts)['reports']
103
+ end
104
+
105
+ # Revoke an ssl cert
106
+ # @param id [Integer] As returned by {#sign}
107
+ # @param reason [String] Reason for revoking. Sectigo's API will return an error if it
108
+ # is blank.
109
+ def revoke id, reason
110
+ post("ssl/v1/revoke/#{id}", reason: reason)
111
+ nil
112
+ end
113
+
114
+ # Sign an SSL cert. Returns the id of the SSL cert
115
+ # @param csr [Varanus::SSL::CSR, OpenSSL::X509::Request, String] CSR to sign
116
+ # @param org_id [Integer] your organization id on cert-manager.com
117
+ # @param opts [Hash]
118
+ # @option opts [String] :comments ('') Limited to 1,024 characters
119
+ # @option opts [String] :external_requester ('') email address associated with cert on
120
+ # cert-manager.com - limited to 512 characters
121
+ # @option opts [String, Integer] :cert_type name(String) or id(Integer) of the cert
122
+ # type to use. If none is specified, Varanus will attempt to find one
123
+ # @option opts [Integer] :years number of years cert should be valid for (this number
124
+ # is multiplied by 365 and used as days)
125
+ # @option opts [Integer] :days number of days cert should be valid for (if none is
126
+ # specified, lowest allowed for the cert type will be used)
127
+ # @return [Integer] Id of SSL cert.
128
+ def sign csr, org_id, opts = {}
129
+ opts[:days] ||= opts[:years] * 365 unless opts[:years].nil?
130
+ csr = Varanus::SSL::CSR.new(csr) unless csr.is_a?(Varanus::SSL::CSR)
131
+ cert_type_id = opts_to_cert_type_id opts, csr
132
+ args = {
133
+ orgId: org_id,
134
+ csr: csr.to_s,
135
+ subjAltNames: csr.subject_alt_names.join(','),
136
+ certType: cert_type_id,
137
+ term: opts_to_term(opts, cert_type_id),
138
+ serverType: -1,
139
+ comments: opts[:comments].to_s[0, 1024],
140
+ externalRequester: opts[:external_requester].to_s[0, 512]
141
+ }
142
+ post('ssl/v1/enroll', args)['sslId']
143
+ end
144
+
145
+ private
146
+
147
+ def cert_type_regexp csr
148
+ return /Wildcard.+SSL/i if csr.all_names.any? { |n| n.start_with?('*.') }
149
+
150
+ return /Multi.?Domain.+SSL/i if csr.subject_alt_names.any?
151
+
152
+ nil
153
+ end
154
+
155
+ def opts_to_cert_type_id opts, csr
156
+ case opts[:cert_type]
157
+ when Integer
158
+ opts[:cert_type]
159
+ when String
160
+ certificate_types.find { |ct| ct['name'] == opts[:cert_type] }['id']
161
+ else
162
+ certificate_type_from_csr(csr, opts[:days])['id']
163
+ end
164
+ end
165
+
166
+ def opts_to_term opts, cert_type_id
167
+ term = opts[:days]
168
+ term ||= certificate_types.find { |ct| ct['id'] == cert_type_id }['terms'].min
169
+ term
170
+ end
171
+
172
+ def _parse_report_opts user_opts
173
+ api_opts = {}
174
+ user_opts.each do |key, val|
175
+ case key
176
+ when :organizationIds, :certificateRequestSource, :serialNumberFormat
177
+ api_opts[key] = val
178
+ when :from, :to
179
+ api_opts[key] = val.strftime('%Y-%m-%d')
180
+ when :certificateStatus
181
+ api_opts[key] = REPORT_CERT_STATUS[val]
182
+ when :certificateDateAttribute
183
+ api_opts[key] = REPORT_CERT_DATE_ATTR[val]
184
+ else
185
+ raise ArgumentError, "Unknown key: #{key.inspect}"
186
+ end
187
+ end
188
+
189
+ api_opts
190
+ end
191
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Varanus
4
+ VERSION = '0.9.0'
5
+ end
data/lib/varanus.rb ADDED
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Interface for Sectigo's (formerly Comodo CA) API.
4
+ class Varanus
5
+ attr_reader :customer_uri, :username, :password
6
+
7
+ # @param customer_uri [String]
8
+ # (see {file:README.md#label-Finding+Organization+Id+-28org_id-29})
9
+ # @param username [String]
10
+ # @param password [String]
11
+ def initialize customer_uri, username, password
12
+ @customer_uri = customer_uri
13
+ @username = username
14
+ @password = password
15
+ end
16
+
17
+ # :nodoc:
18
+ def connection
19
+ @connection ||= Faraday.new(url: 'https://cert-manager.com/api',
20
+ request: { timeout: 300 }) do |conn|
21
+ conn.request :json
22
+ conn.response :json, content_type: /\bjson$/
23
+
24
+ conn.headers['login'] = @username
25
+ conn.headers['password'] = @password
26
+ conn.headers['customerUri'] = @customer_uri
27
+
28
+ conn.adapter Faraday.default_adapter
29
+ end
30
+ end
31
+
32
+ # Retrive DCV instance
33
+ # @return [Varanus::DCV]
34
+ def dcv
35
+ @dcv ||= DCV.new(self)
36
+ end
37
+
38
+ # Retrieve Domain instance
39
+ # @return [Varanus::Domain]
40
+ def domain
41
+ @domain ||= Domain.new(self)
42
+ end
43
+
44
+ # Retrieve Organization instance
45
+ # @return [Varanus::Organization]
46
+ def organization
47
+ @organization ||= Organization.new(self)
48
+ end
49
+
50
+ # DEPRECATED
51
+ def reports
52
+ @reports ||= Reports.new(self)
53
+ end
54
+
55
+ # Retrive SSL instance
56
+ # @return [Varanus::SSL]
57
+ def ssl
58
+ @ssl ||= SSL.new(self)
59
+ end
60
+ end
61
+
62
+ # stdlib/gem requires
63
+ require 'faraday'
64
+ require 'openssl'
65
+ require 'savon'
66
+
67
+ # Require other files in this gem
68
+ require 'varanus/error'
69
+ require 'varanus/rest_resource'
70
+ require 'varanus/dcv'
71
+ require 'varanus/domain'
72
+ require 'varanus/organization'
73
+ require 'varanus/reports'
74
+ require 'varanus/ssl'
75
+ require 'varanus/ssl/csr'
76
+ require 'varanus/version'
data/varanus.gemspec ADDED
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'varanus/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'varanus'
9
+ spec.version = Varanus::VERSION
10
+ spec.authors = ['Sean Dilda']
11
+ spec.email = ['sean@duke.edu']
12
+
13
+ spec.summary = "Interface for Sectigo's (formerly Comodo CA) API."
14
+ spec.description = <<~DESCRIPTION
15
+ This gem provides an interface to Sectigo's (formerly Comodo CA) APIs for working
16
+ with SSL/TLS certificates as well as its reporting API.
17
+
18
+ Support for Sectigo's other APIs (S/MIME, code signing, device certificates, etc) may
19
+ be added at a later date.
20
+ DESCRIPTION
21
+ spec.homepage = 'https://github.com/duke-automation/varanus'
22
+ spec.license = 'MIT'
23
+
24
+ # Specify which files should be added to the gem when it is released.
25
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
26
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
27
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
28
+ end
29
+ spec.require_paths = ['lib']
30
+ spec.required_ruby_version = '>= 2.5.0'
31
+
32
+ spec.add_development_dependency 'bundler', '~> 2.0'
33
+ spec.add_development_dependency 'minitest', '~> 5.0'
34
+ spec.add_development_dependency 'minitest-rg'
35
+ spec.add_development_dependency 'mocha'
36
+ spec.add_development_dependency 'rake', '~> 10.0'
37
+ spec.add_development_dependency 'rubocop'
38
+ spec.add_development_dependency 'simplecov'
39
+ spec.add_development_dependency 'webmock'
40
+ spec.add_development_dependency 'yard'
41
+
42
+ spec.add_runtime_dependency 'faraday', '~> 2.0'
43
+ spec.add_runtime_dependency 'savon', '~> 2.0'
44
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: varanus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Dilda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-27 00:00:00.000000000 Z
11
+ date: 2026-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -140,30 +140,16 @@ dependencies:
140
140
  name: faraday
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :runtime
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: faraday_middleware
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
143
+ - - "~>"
158
144
  - !ruby/object:Gem::Version
159
- version: '0'
145
+ version: '2.0'
160
146
  type: :runtime
161
147
  prerelease: false
162
148
  version_requirements: !ruby/object:Gem::Requirement
163
149
  requirements:
164
- - - ">="
150
+ - - "~>"
165
151
  - !ruby/object:Gem::Version
166
- version: '0'
152
+ version: '2.0'
167
153
  - !ruby/object:Gem::Dependency
168
154
  name: savon
169
155
  requirement: !ruby/object:Gem::Requirement
@@ -189,7 +175,31 @@ email:
189
175
  executables: []
190
176
  extensions: []
191
177
  extra_rdoc_files: []
192
- files: []
178
+ files:
179
+ - ".codeclimate.yml"
180
+ - ".gitignore"
181
+ - ".rubocop.yml"
182
+ - ".travis.yml"
183
+ - CHANGELOG.md
184
+ - Gemfile
185
+ - Gemfile.lock
186
+ - LICENSE.txt
187
+ - README.md
188
+ - Rakefile
189
+ - bin/console
190
+ - bin/setup
191
+ - docker-compose.yml
192
+ - lib/varanus.rb
193
+ - lib/varanus/dcv.rb
194
+ - lib/varanus/domain.rb
195
+ - lib/varanus/error.rb
196
+ - lib/varanus/organization.rb
197
+ - lib/varanus/reports.rb
198
+ - lib/varanus/rest_resource.rb
199
+ - lib/varanus/ssl.rb
200
+ - lib/varanus/ssl/csr.rb
201
+ - lib/varanus/version.rb
202
+ - varanus.gemspec
193
203
  homepage: https://github.com/duke-automation/varanus
194
204
  licenses:
195
205
  - MIT
@@ -209,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
209
219
  - !ruby/object:Gem::Version
210
220
  version: '0'
211
221
  requirements: []
212
- rubygems_version: 3.3.27
222
+ rubygems_version: 3.4.20
213
223
  signing_key:
214
224
  specification_version: 4
215
225
  summary: Interface for Sectigo's (formerly Comodo CA) API.