varanus 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c5717bc294e05caa49007dbf36c638ecf3a1d3e192aee421e51a73fec58246c
4
- data.tar.gz: 54f6feea0b5b692d415dd2f9d5eff9d0d088f29e26d54a700467494f11904048
3
+ metadata.gz: 806b45f188f1d18b63d3a86473ecc2574d8cd310edebdb990ffa6d7e7ff954b2
4
+ data.tar.gz: 5dcdf1d543e85c8b4e4c63e843ebafc4fce3920c7b5a678ed242c7d0851c85d1
5
5
  SHA512:
6
- metadata.gz: 246eeabfd08d59b01f5b8e6cca4d5ec8b4c7a73223ee34d8ac86a1d459d286fdf965ed410a381b2312ab72e97f3c0b65dc0da77c8b31776e53253f10b9003a05
7
- data.tar.gz: cdf0e60e8894b50e55f81901f0d441a7a3edf376856de12ea4a0bfc845267c3026926dcafabec14e7aebaf1292a25e6c8c0e76cbdfd9f346a9b18a3828021543
6
+ metadata.gz: 21274fac02943441d901d35402c6af6cf5c60e940c606033bf75969abe33f086137512e91691f58fb022726c91cb1f795a89b7bfbd807f625b548d55315ba293
7
+ data.tar.gz: 8259aa8ec33a5a479b73c43934cae97e491d82e3330e71ed29480fab07c37fefdb39c3e2070e002263235f739c5c3b96383c982ba732fa87a49022996daf6a92
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,45 @@
1
+ ### Version 0.8.1 (2024-09-27)
2
+ * Fix gem build issues
3
+
4
+ ### Version 0.8.0 (2024-09-27)
5
+ * Varanus::SSL::CSR - improve support for subclassing
6
+ * Varanus::SSL::CSR.generate - support an EC key being passed in
7
+
8
+ ### Version 0.7.1 (2022-01-31)
9
+ * Varanus::SSL#certificate_types_standard - also exclude 'Extended Validation'
10
+
11
+ ### Version 0.7.0 (2020-02-03)
12
+ * Add Varanus::Domain#report
13
+
14
+ ### Version 0.6.0 (2020-02-01)
15
+ * Add Varanus::SSL#report
16
+ * Varanus::Reports (Varanus#reports) is now deprecated.
17
+
18
+ ### Version 0.5.1 (2021-01-28)
19
+ * Varanus::SSL::CSR - support EC certs
20
+
21
+ ### Version 0.5.0 (2021-01-26)
22
+ * Add Varanus::Domain
23
+ * Add Varanus::SSL#list and Varanus::SSL#info
24
+ * Add Varanus::Organization
25
+
26
+ ### 0.4.0 (2021-01-06)
27
+ * Add Varanus::DCV
28
+
29
+ ### 0.3.1 (2020-10-14)
30
+ * Fix issue when Sectigo reports two identical 'Short Life' certs
31
+
32
+ ### 0.3.0 (2020-08-24)
33
+ * Add support for new 'Short Life' certs
34
+
35
+ ### 0.2.1 (2018-11-13)
36
+ * Increase timeout value for SSL requests
37
+
38
+ ### 0.2.0 (2018-11-09)
39
+ * Added Varanus::SSL::CSR.generate
40
+ * Added Reports
41
+ * Varanus::Reports#ssl - list of SSL/TLS certs
42
+ * Varanus::Reports#domains - list of domains validated with DCV
43
+
44
+ ### 0.1.0 (2018-11-07)
45
+ * 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,158 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ varanus (0.8.1)
5
+ faraday
6
+ faraday_middleware
7
+ savon (~> 2.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ addressable (2.8.7)
13
+ public_suffix (>= 2.0.2, < 7.0)
14
+ akami (1.3.3)
15
+ base64
16
+ gyoku (>= 0.4.0)
17
+ nokogiri
18
+ ast (2.4.2)
19
+ base64 (0.2.0)
20
+ bigdecimal (3.1.8)
21
+ builder (3.3.0)
22
+ crack (1.0.0)
23
+ bigdecimal
24
+ rexml
25
+ date (3.3.4)
26
+ docile (1.4.1)
27
+ faraday (1.10.4)
28
+ faraday-em_http (~> 1.0)
29
+ faraday-em_synchrony (~> 1.0)
30
+ faraday-excon (~> 1.1)
31
+ faraday-httpclient (~> 1.0)
32
+ faraday-multipart (~> 1.0)
33
+ faraday-net_http (~> 1.0)
34
+ faraday-net_http_persistent (~> 1.0)
35
+ faraday-patron (~> 1.0)
36
+ faraday-rack (~> 1.0)
37
+ faraday-retry (~> 1.0)
38
+ ruby2_keywords (>= 0.0.4)
39
+ faraday-em_http (1.0.0)
40
+ faraday-em_synchrony (1.0.0)
41
+ faraday-excon (1.1.0)
42
+ faraday-httpclient (1.0.1)
43
+ faraday-multipart (1.0.4)
44
+ multipart-post (~> 2)
45
+ faraday-net_http (1.0.2)
46
+ faraday-net_http_persistent (1.2.0)
47
+ faraday-patron (1.0.0)
48
+ faraday-rack (1.0.0)
49
+ faraday-retry (1.0.3)
50
+ faraday_middleware (1.2.1)
51
+ faraday (~> 1.0)
52
+ gyoku (1.4.0)
53
+ builder (>= 2.1.2)
54
+ rexml (~> 3.0)
55
+ hashdiff (1.1.1)
56
+ httpi (4.0.4)
57
+ base64
58
+ mutex_m
59
+ nkf
60
+ rack (>= 2.0, < 4)
61
+ json (2.7.2)
62
+ language_server-protocol (3.17.0.3)
63
+ mail (2.8.1)
64
+ mini_mime (>= 0.1.1)
65
+ net-imap
66
+ net-pop
67
+ net-smtp
68
+ mini_mime (1.1.5)
69
+ minitest (5.25.1)
70
+ minitest-rg (5.3.0)
71
+ minitest (~> 5.0)
72
+ mocha (2.4.5)
73
+ ruby2_keywords (>= 0.0.5)
74
+ multipart-post (2.4.1)
75
+ mutex_m (0.2.0)
76
+ net-imap (0.4.16)
77
+ date
78
+ net-protocol
79
+ net-pop (0.1.2)
80
+ net-protocol
81
+ net-protocol (0.2.2)
82
+ timeout
83
+ net-smtp (0.5.0)
84
+ net-protocol
85
+ nkf (0.2.0)
86
+ nokogiri (1.16.7-x86_64-linux)
87
+ racc (~> 1.4)
88
+ nori (2.7.1)
89
+ bigdecimal
90
+ parallel (1.26.3)
91
+ parser (3.3.5.0)
92
+ ast (~> 2.4.1)
93
+ racc
94
+ public_suffix (6.0.1)
95
+ racc (1.8.1)
96
+ rack (3.1.7)
97
+ rainbow (3.1.1)
98
+ rake (10.5.0)
99
+ regexp_parser (2.9.2)
100
+ rexml (3.3.7)
101
+ rubocop (1.66.1)
102
+ json (~> 2.3)
103
+ language_server-protocol (>= 3.17.0)
104
+ parallel (~> 1.10)
105
+ parser (>= 3.3.0.2)
106
+ rainbow (>= 2.2.2, < 4.0)
107
+ regexp_parser (>= 2.4, < 3.0)
108
+ rubocop-ast (>= 1.32.2, < 2.0)
109
+ ruby-progressbar (~> 1.7)
110
+ unicode-display_width (>= 2.4.0, < 3.0)
111
+ rubocop-ast (1.32.3)
112
+ parser (>= 3.3.1.0)
113
+ ruby-progressbar (1.13.0)
114
+ ruby2_keywords (0.0.5)
115
+ savon (2.15.1)
116
+ akami (~> 1.2)
117
+ builder (>= 2.1.2)
118
+ gyoku (~> 1.2)
119
+ httpi (>= 4, < 5)
120
+ mail (~> 2.5)
121
+ nokogiri (>= 1.8.1)
122
+ nori (~> 2.4)
123
+ wasabi (>= 3.7, < 6)
124
+ simplecov (0.22.0)
125
+ docile (~> 1.1)
126
+ simplecov-html (~> 0.11)
127
+ simplecov_json_formatter (~> 0.1)
128
+ simplecov-html (0.13.1)
129
+ simplecov_json_formatter (0.1.4)
130
+ timeout (0.4.1)
131
+ unicode-display_width (2.6.0)
132
+ wasabi (5.0.3)
133
+ addressable
134
+ faraday (>= 1.9, < 3)
135
+ nokogiri (>= 1.13.9)
136
+ webmock (3.23.1)
137
+ addressable (>= 2.8.0)
138
+ crack (>= 0.3.2)
139
+ hashdiff (>= 0.4.0, < 2.0.0)
140
+ yard (0.9.37)
141
+
142
+ PLATFORMS
143
+ x86_64-linux
144
+
145
+ DEPENDENCIES
146
+ bundler (~> 2.0)
147
+ minitest (~> 5.0)
148
+ minitest-rg
149
+ mocha
150
+ rake (~> 10.0)
151
+ rubocop
152
+ simplecov
153
+ varanus!
154
+ webmock
155
+ yard
156
+
157
+ BUNDLED WITH
158
+ 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.8.1'
5
+ end
data/lib/varanus.rb ADDED
@@ -0,0 +1,77 @@
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 'faraday_middleware'
65
+ require 'openssl'
66
+ require 'savon'
67
+
68
+ # Require other files in this gem
69
+ require 'varanus/error'
70
+ require 'varanus/rest_resource'
71
+ require 'varanus/dcv'
72
+ require 'varanus/domain'
73
+ require 'varanus/organization'
74
+ require 'varanus/reports'
75
+ require 'varanus/ssl'
76
+ require 'varanus/ssl/csr'
77
+ require 'varanus/version'
data/varanus.gemspec ADDED
@@ -0,0 +1,45 @@
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'
43
+ spec.add_runtime_dependency 'faraday_middleware'
44
+ spec.add_runtime_dependency 'savon', '~> 2.0'
45
+ end
metadata CHANGED
@@ -1,11 +1,11 @@
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.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Dilda
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2024-09-27 00:00:00.000000000 Z
@@ -189,12 +189,36 @@ email:
189
189
  executables: []
190
190
  extensions: []
191
191
  extra_rdoc_files: []
192
- files: []
192
+ files:
193
+ - ".codeclimate.yml"
194
+ - ".gitignore"
195
+ - ".rubocop.yml"
196
+ - ".travis.yml"
197
+ - CHANGELOG.md
198
+ - Gemfile
199
+ - Gemfile.lock
200
+ - LICENSE.txt
201
+ - README.md
202
+ - Rakefile
203
+ - bin/console
204
+ - bin/setup
205
+ - docker-compose.yml
206
+ - lib/varanus.rb
207
+ - lib/varanus/dcv.rb
208
+ - lib/varanus/domain.rb
209
+ - lib/varanus/error.rb
210
+ - lib/varanus/organization.rb
211
+ - lib/varanus/reports.rb
212
+ - lib/varanus/rest_resource.rb
213
+ - lib/varanus/ssl.rb
214
+ - lib/varanus/ssl/csr.rb
215
+ - lib/varanus/version.rb
216
+ - varanus.gemspec
193
217
  homepage: https://github.com/duke-automation/varanus
194
218
  licenses:
195
219
  - MIT
196
220
  metadata: {}
197
- post_install_message:
221
+ post_install_message:
198
222
  rdoc_options: []
199
223
  require_paths:
200
224
  - lib
@@ -209,8 +233,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
209
233
  - !ruby/object:Gem::Version
210
234
  version: '0'
211
235
  requirements: []
212
- rubygems_version: 3.3.27
213
- signing_key:
236
+ rubygems_version: 3.3.5
237
+ signing_key:
214
238
  specification_version: 4
215
239
  summary: Interface for Sectigo's (formerly Comodo CA) API.
216
240
  test_files: []