varanus 0.2.1 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +7 -6
- data/.travis.yml +1 -2
- data/CHANGELOG.md +18 -1
- data/Gemfile.lock +52 -47
- data/docker-compose.yml +1 -1
- data/lib/varanus.rb +37 -0
- data/lib/varanus/dcv.rb +62 -0
- data/lib/varanus/domain.rb +42 -0
- data/lib/varanus/organization.rb +13 -0
- data/lib/varanus/rest_resource.rb +56 -0
- data/lib/varanus/ssl.rb +42 -60
- data/lib/varanus/ssl/csr.rb +13 -6
- data/lib/varanus/version.rb +1 -1
- data/varanus.gemspec +1 -3
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67c52ba9ede6f495a05841bacfbf3046cb41b45cd8bb1d4ef8a1c7491e735644
|
4
|
+
data.tar.gz: 921e5bd93bf8caa0378ba15f45276b8100c19239d28e3e22b68e3ae76fa85da1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2cf7fd0e7ec49ec4b9f6bdef82aae9f7cf8d05f0343cce7d8595dfd6a975cf0fc983045997ec0f6cbc8425b8935ff66bc3a7846cd321a55789508cb4ee03fce
|
7
|
+
data.tar.gz: c02ba0dfc6a9132204d50f3bc1453b878c73f34ca981ead6ffd29c35bc91fe637922085ac28ceb831fa0b22fe5fe1a3b61679314b99255e00774346689dc31d8
|
data/.rubocop.yml
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
AllCops:
|
2
|
-
|
2
|
+
NewCops: disable
|
3
|
+
TargetRubyVersion: 2.5
|
3
4
|
|
4
5
|
Bundler/OrderedGems:
|
5
6
|
AutoCorrect: false
|
6
7
|
|
8
|
+
Layout/LineLength:
|
9
|
+
Max: 90
|
10
|
+
Exclude:
|
11
|
+
- 'test/**/*'
|
12
|
+
|
7
13
|
Metrics/AbcSize:
|
8
14
|
Max: 25
|
9
15
|
Exclude:
|
@@ -14,11 +20,6 @@ Metrics/ClassLength:
|
|
14
20
|
Exclude:
|
15
21
|
- 'test/**/*'
|
16
22
|
|
17
|
-
Metrics/LineLength:
|
18
|
-
Max: 90
|
19
|
-
Exclude:
|
20
|
-
- 'test/**/*'
|
21
|
-
|
22
23
|
Metrics/MethodLength:
|
23
24
|
Max: 20
|
24
25
|
Exclude:
|
data/.travis.yml
CHANGED
@@ -6,10 +6,9 @@ sudo: false
|
|
6
6
|
language: ruby
|
7
7
|
cache: bundler
|
8
8
|
rvm:
|
9
|
-
- 2.3
|
10
|
-
- 2.4
|
11
9
|
- 2.5
|
12
10
|
- 2.6
|
11
|
+
- 2.7
|
13
12
|
before_install: gem install bundler -v 1.16.5
|
14
13
|
before_script:
|
15
14
|
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,21 @@
|
|
1
|
-
### 0.
|
1
|
+
### Version 0.5.1 (2021-01-28)
|
2
|
+
* Varanus::SSL::CSR - support EC certs
|
3
|
+
|
4
|
+
### Version 0.5.0 (2021-01-26)
|
5
|
+
* Add Varanus::Domain
|
6
|
+
* Add Varanus::SSL#list and Varanus::SSL#info
|
7
|
+
* Add Varanus::Organization
|
8
|
+
|
9
|
+
### 0.4.0 (2021-01-06)
|
10
|
+
* Add Varanus::DCV
|
11
|
+
|
12
|
+
### 0.3.1 (2020-10-14)
|
13
|
+
* Fix issue when Sectigo reports two identical 'Short Life' certs
|
14
|
+
|
15
|
+
### 0.3.0 (2020-08-24)
|
16
|
+
* Add support for new 'Short Life' certs
|
17
|
+
|
18
|
+
### 0.2.1 (2018-11-13)
|
2
19
|
* Increase timeout value for SSL requests
|
3
20
|
|
4
21
|
### 0.2.0 (2018-11-09)
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
varanus (0.
|
4
|
+
varanus (0.5.1)
|
5
5
|
faraday
|
6
6
|
faraday_middleware
|
7
7
|
savon (~> 2.0)
|
@@ -9,58 +9,61 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
addressable (2.
|
13
|
-
public_suffix (>= 2.0.2, <
|
12
|
+
addressable (2.7.0)
|
13
|
+
public_suffix (>= 2.0.2, < 5.0)
|
14
14
|
akami (1.3.1)
|
15
15
|
gyoku (>= 0.4.0)
|
16
16
|
nokogiri
|
17
|
-
ast (2.4.
|
18
|
-
builder (3.2.
|
19
|
-
crack (0.4.
|
20
|
-
|
21
|
-
docile (1.3.
|
22
|
-
faraday (
|
17
|
+
ast (2.4.1)
|
18
|
+
builder (3.2.4)
|
19
|
+
crack (0.4.5)
|
20
|
+
rexml
|
21
|
+
docile (1.3.4)
|
22
|
+
faraday (1.3.0)
|
23
|
+
faraday-net_http (~> 1.0)
|
23
24
|
multipart-post (>= 1.2, < 3)
|
24
|
-
|
25
|
-
|
25
|
+
ruby2_keywords
|
26
|
+
faraday-net_http (1.0.0)
|
27
|
+
faraday_middleware (1.0.0)
|
28
|
+
faraday (~> 1.0)
|
26
29
|
gyoku (1.3.1)
|
27
30
|
builder (>= 2.1.2)
|
28
|
-
hashdiff (0.
|
29
|
-
httpi (2.4.
|
31
|
+
hashdiff (1.0.1)
|
32
|
+
httpi (2.4.5)
|
30
33
|
rack
|
31
34
|
socksify
|
32
|
-
|
33
|
-
json (2.1.0)
|
34
|
-
metaclass (0.0.4)
|
35
|
-
mini_portile2 (2.3.0)
|
36
|
-
minitest (5.11.3)
|
35
|
+
minitest (5.14.3)
|
37
36
|
minitest-rg (5.2.0)
|
38
37
|
minitest (~> 5.0)
|
39
|
-
mocha (1.
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
mini_portile2 (~> 2.3.0)
|
38
|
+
mocha (1.12.0)
|
39
|
+
multipart-post (2.1.1)
|
40
|
+
nokogiri (1.11.1-x86_64-linux)
|
41
|
+
racc (~> 1.4)
|
44
42
|
nori (2.6.0)
|
45
|
-
parallel (1.
|
46
|
-
parser (
|
47
|
-
ast (~> 2.4.
|
48
|
-
|
49
|
-
|
50
|
-
rack (2.
|
43
|
+
parallel (1.20.1)
|
44
|
+
parser (3.0.0.0)
|
45
|
+
ast (~> 2.4.1)
|
46
|
+
public_suffix (4.0.6)
|
47
|
+
racc (1.5.2)
|
48
|
+
rack (2.2.3)
|
51
49
|
rainbow (3.0.0)
|
52
50
|
rake (10.5.0)
|
53
|
-
|
54
|
-
|
51
|
+
regexp_parser (2.0.3)
|
52
|
+
rexml (3.2.4)
|
53
|
+
rubocop (1.7.0)
|
55
54
|
parallel (~> 1.10)
|
56
|
-
parser (>= 2.
|
57
|
-
powerpack (~> 0.1)
|
55
|
+
parser (>= 2.7.1.5)
|
58
56
|
rainbow (>= 2.2.2, < 4.0)
|
57
|
+
regexp_parser (>= 1.8, < 3.0)
|
58
|
+
rexml
|
59
|
+
rubocop-ast (>= 1.2.0, < 2.0)
|
59
60
|
ruby-progressbar (~> 1.7)
|
60
|
-
unicode-display_width (
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
62
|
+
rubocop-ast (1.4.0)
|
63
|
+
parser (>= 2.7.1.5)
|
64
|
+
ruby-progressbar (1.11.0)
|
65
|
+
ruby2_keywords (0.0.2)
|
66
|
+
savon (2.12.1)
|
64
67
|
akami (~> 1.2)
|
65
68
|
builder (>= 2.1.2)
|
66
69
|
gyoku (~> 1.2)
|
@@ -68,21 +71,23 @@ GEM
|
|
68
71
|
nokogiri (>= 1.8.1)
|
69
72
|
nori (~> 2.4)
|
70
73
|
wasabi (~> 3.4)
|
71
|
-
simplecov (0.
|
74
|
+
simplecov (0.21.1)
|
72
75
|
docile (~> 1.1)
|
73
|
-
|
74
|
-
|
75
|
-
simplecov-html (0.
|
76
|
+
simplecov-html (~> 0.11)
|
77
|
+
simplecov_json_formatter (~> 0.1)
|
78
|
+
simplecov-html (0.12.3)
|
79
|
+
simplecov_json_formatter (0.1.2)
|
76
80
|
socksify (1.7.1)
|
77
|
-
unicode-display_width (1.
|
78
|
-
wasabi (3.
|
81
|
+
unicode-display_width (1.7.0)
|
82
|
+
wasabi (3.6.1)
|
83
|
+
addressable
|
79
84
|
httpi (~> 2.0)
|
80
85
|
nokogiri (>= 1.4.2)
|
81
|
-
webmock (3.
|
86
|
+
webmock (3.11.0)
|
82
87
|
addressable (>= 2.3.6)
|
83
88
|
crack (>= 0.3.2)
|
84
|
-
hashdiff
|
85
|
-
yard (0.9.
|
89
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
90
|
+
yard (0.9.26)
|
86
91
|
|
87
92
|
PLATFORMS
|
88
93
|
ruby
|
@@ -100,4 +105,4 @@ DEPENDENCIES
|
|
100
105
|
yard
|
101
106
|
|
102
107
|
BUNDLED WITH
|
103
|
-
1.17.
|
108
|
+
1.17.3
|
data/docker-compose.yml
CHANGED
data/lib/varanus.rb
CHANGED
@@ -14,6 +14,39 @@ class Varanus
|
|
14
14
|
@password = password
|
15
15
|
end
|
16
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
|
+
|
17
50
|
# Retrieve Reports instance
|
18
51
|
# @return [Varanus::Reports]
|
19
52
|
def reports
|
@@ -35,6 +68,10 @@ require 'savon'
|
|
35
68
|
|
36
69
|
# Require other files in this gem
|
37
70
|
require 'varanus/error'
|
71
|
+
require 'varanus/rest_resource'
|
72
|
+
require 'varanus/dcv'
|
73
|
+
require 'varanus/domain'
|
74
|
+
require 'varanus/organization'
|
38
75
|
require 'varanus/reports'
|
39
76
|
require 'varanus/ssl'
|
40
77
|
require 'varanus/ssl/csr'
|
data/lib/varanus/dcv.rb
ADDED
@@ -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,42 @@
|
|
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
|
+
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,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
|
data/lib/varanus/ssl.rb
CHANGED
@@ -2,35 +2,39 @@
|
|
2
2
|
|
3
3
|
# An connection to the SSL/TSL API. This should not be initialized directly. Instead,
|
4
4
|
# use Varanus#ssl
|
5
|
-
class Varanus::SSL
|
6
|
-
# @note Do not call this directly. Use {Varanus#ssl} to initialize
|
7
|
-
def initialize varanus
|
8
|
-
@varanus = varanus
|
9
|
-
end
|
10
|
-
|
5
|
+
class Varanus::SSL < Varanus::RestResource
|
11
6
|
# Returns the option from #certificate_types that best matches the csr.
|
12
7
|
# @param csr [Varanus::SSL::CSR]
|
13
8
|
# @return [Hash] The option from {#certificate_types} that best matches the csr
|
14
|
-
def certificate_type_from_csr csr
|
15
|
-
|
16
|
-
types
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
types.find do |ct|
|
25
|
-
ct['name'] =~ /\bSSL\b/ && ct['name'] !~ /(?:Multi.?Domain|Wildcard)/i
|
26
|
-
end
|
9
|
+
def certificate_type_from_csr csr, days = nil
|
10
|
+
types = certificate_types_standard(days)
|
11
|
+
return types.first if types.length <= 1
|
12
|
+
|
13
|
+
regexp = cert_type_regexp(csr)
|
14
|
+
typ = types.find { |ct| ct['name'] =~ regexp } if regexp
|
15
|
+
return typ unless typ.nil?
|
16
|
+
|
17
|
+
types.find do |ct|
|
18
|
+
ct['name'] =~ /\bSSL\b/ && ct['name'] !~ /(?:Multi.?Domain|Wildcard)/i
|
27
19
|
end
|
28
20
|
end
|
29
21
|
|
30
22
|
# Certificate types that can be used to sign a cert
|
31
23
|
# @return [Array<Hash>]
|
32
24
|
def certificate_types
|
33
|
-
@certificate_types ||= get('types')
|
25
|
+
@certificate_types ||= get('ssl/v1/types')
|
26
|
+
end
|
27
|
+
|
28
|
+
# Return Array of certificate types based on standard sorting.
|
29
|
+
# @param days [Integer] if present, only include types that support the given day count
|
30
|
+
# @return [Array<Hash>]
|
31
|
+
def certificate_types_standard days = nil
|
32
|
+
types = certificate_types.reject do |ct|
|
33
|
+
ct['name'] =~ /\b(?:EV|ECC|AMT|Elite)\b/
|
34
|
+
end
|
35
|
+
types = types.select! { |t| t['terms'].include? days } unless days.nil?
|
36
|
+
|
37
|
+
types
|
34
38
|
end
|
35
39
|
|
36
40
|
# Retrieves the cert.
|
@@ -48,7 +52,16 @@ class Varanus::SSL
|
|
48
52
|
# @raise [Varanus::Error::StillProcessing] Cert is still being signed
|
49
53
|
# @return [String] Certificate
|
50
54
|
def collect id, type = 'x509'
|
51
|
-
get("collect/#{id}/#{type}")
|
55
|
+
get("ssl/v1/collect/#{id}/#{type}")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns info on the SSL certificate of the given name
|
59
|
+
def info id
|
60
|
+
get("ssl/v1/#{id}")
|
61
|
+
end
|
62
|
+
|
63
|
+
def list opts = {}
|
64
|
+
get_with_size_and_position('ssl/v1', opts)
|
52
65
|
end
|
53
66
|
|
54
67
|
# Revoke an ssl cert
|
@@ -56,7 +69,7 @@ class Varanus::SSL
|
|
56
69
|
# @param reason [String] Reason for revoking. Sectigo's API will return an error if it
|
57
70
|
# is blank.
|
58
71
|
def revoke id, reason
|
59
|
-
post("revoke/#{id}", reason: reason)
|
72
|
+
post("ssl/v1/revoke/#{id}", reason: reason)
|
60
73
|
nil
|
61
74
|
end
|
62
75
|
|
@@ -75,6 +88,7 @@ class Varanus::SSL
|
|
75
88
|
# specified, lowest allowed for the cert type will be used)
|
76
89
|
# @return [Integer] Id of SSL cert.
|
77
90
|
def sign csr, org_id, opts = {}
|
91
|
+
opts[:days] ||= opts[:years] * 365 unless opts[:years].nil?
|
78
92
|
csr = Varanus::SSL::CSR.new(csr) unless csr.is_a?(Varanus::SSL::CSR)
|
79
93
|
cert_type_id = opts_to_cert_type_id opts, csr
|
80
94
|
args = {
|
@@ -87,42 +101,17 @@ class Varanus::SSL
|
|
87
101
|
comments: opts[:comments].to_s[0, 1024],
|
88
102
|
externalRequester: opts[:external_requester].to_s[0, 512]
|
89
103
|
}
|
90
|
-
post('enroll', args)['sslId']
|
104
|
+
post('ssl/v1/enroll', args)['sslId']
|
91
105
|
end
|
92
106
|
|
93
107
|
private
|
94
108
|
|
95
|
-
def
|
96
|
-
|
97
|
-
return unless body.is_a?(Hash)
|
98
|
-
return if body['code'].nil?
|
99
|
-
|
100
|
-
klass = Varanus::Error
|
101
|
-
if body['code'] == 0 && body['description'] =~ /process/
|
102
|
-
klass = Varanus::Error::StillProcessing
|
103
|
-
end
|
104
|
-
|
105
|
-
raise klass.new(body['code'], body['description'])
|
106
|
-
end
|
109
|
+
def cert_type_regexp csr
|
110
|
+
return /Wildcard.+SSL/i if csr.all_names.any? { |n| n.start_with?('*.') }
|
107
111
|
|
108
|
-
|
109
|
-
@connection ||= Faraday.new(url: 'https://cert-manager.com/api/ssl/v1',
|
110
|
-
request: { timeout: 300 }) do |conn|
|
111
|
-
conn.request :json
|
112
|
-
conn.response :json, content_type: /\bjson$/
|
112
|
+
return /Multi.?Domain.+SSL/i if csr.subject_alt_names.any?
|
113
113
|
|
114
|
-
|
115
|
-
conn.headers['password'] = @varanus.password
|
116
|
-
conn.headers['customerUri'] = @varanus.customer_uri
|
117
|
-
|
118
|
-
conn.adapter Faraday.default_adapter
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def get path
|
123
|
-
result = connection.get(path)
|
124
|
-
check_result result
|
125
|
-
result.body
|
114
|
+
nil
|
126
115
|
end
|
127
116
|
|
128
117
|
def opts_to_cert_type_id opts, csr
|
@@ -132,19 +121,12 @@ class Varanus::SSL
|
|
132
121
|
when String
|
133
122
|
certificate_types.find { |ct| ct['name'] == opts[:cert_type] }['id']
|
134
123
|
else
|
135
|
-
certificate_type_from_csr(csr)['id']
|
124
|
+
certificate_type_from_csr(csr, opts[:days])['id']
|
136
125
|
end
|
137
126
|
end
|
138
127
|
|
139
|
-
def post path, *args
|
140
|
-
result = connection.post(path, *args)
|
141
|
-
check_result result
|
142
|
-
result.body
|
143
|
-
end
|
144
|
-
|
145
128
|
def opts_to_term opts, cert_type_id
|
146
129
|
term = opts[:days]
|
147
|
-
term ||= opts[:years] * 365 unless opts[:years].nil?
|
148
130
|
term ||= certificate_types.find { |ct| ct['id'] == cert_type_id }['terms'].min
|
149
131
|
term
|
150
132
|
end
|
data/lib/varanus/ssl/csr.rb
CHANGED
@@ -25,18 +25,23 @@ class Varanus::SSL::CSR
|
|
25
25
|
request = OpenSSL::X509::Request.new
|
26
26
|
request.version = 0
|
27
27
|
request.subject = OpenSSL::X509::Name.parse subject.map { |k, v| "/#{k}=#{v}" }.join
|
28
|
+
request.add_attribute names_to_san_attribute(names)
|
29
|
+
request.public_key = key.public_key
|
30
|
+
|
31
|
+
request.sign(key, OpenSSL::Digest::SHA256.new)
|
32
|
+
|
33
|
+
[key, Varanus::SSL::CSR.new(request)]
|
34
|
+
end
|
28
35
|
|
29
|
-
|
36
|
+
# :nodoc:
|
37
|
+
# Create a Subject Alternate Names attribute from an Array of dns names
|
38
|
+
def self.names_to_san_attribute names
|
30
39
|
ef = OpenSSL::X509::ExtensionFactory.new
|
31
40
|
name_str = names.map { |n| "DNS:#{n}" }.join(', ')
|
32
41
|
ext = ef.create_extension('subjectAltName', name_str, false)
|
33
42
|
seq = OpenSSL::ASN1::Sequence([ext])
|
34
43
|
ext_req = OpenSSL::ASN1::Set([seq])
|
35
|
-
|
36
|
-
|
37
|
-
request.public_key = key.public_key
|
38
|
-
request.sign(key, OpenSSL::Digest::SHA256.new)
|
39
|
-
[key, Varanus::SSL::CSR.new(request)]
|
44
|
+
OpenSSL::X509::Attribute.new('extReq', ext_req)
|
40
45
|
end
|
41
46
|
|
42
47
|
# Common Name (CN) for cert.
|
@@ -82,6 +87,8 @@ class Varanus::SSL::CSR
|
|
82
87
|
@request.public_key.n.num_bytes * 8
|
83
88
|
when OpenSSL::PKey::DSA
|
84
89
|
@request.public_key.p.num_bytes * 8
|
90
|
+
when OpenSSL::PKey::EC
|
91
|
+
@request.public_key.group.degree
|
85
92
|
else
|
86
93
|
raise "Unknown public key type: #{@request.public_key.class}"
|
87
94
|
end
|
data/lib/varanus/version.rb
CHANGED
data/varanus.gemspec
CHANGED
@@ -4,7 +4,6 @@ lib = File.expand_path('lib', __dir__)
|
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require 'varanus/version'
|
6
6
|
|
7
|
-
# rubocop:disable Metrics/BlockLength
|
8
7
|
Gem::Specification.new do |spec|
|
9
8
|
spec.name = 'varanus'
|
10
9
|
spec.version = Varanus::VERSION
|
@@ -28,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
28
27
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
29
28
|
end
|
30
29
|
spec.require_paths = ['lib']
|
31
|
-
spec.required_ruby_version = '>= 2.
|
30
|
+
spec.required_ruby_version = '>= 2.5.0'
|
32
31
|
|
33
32
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
34
33
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
@@ -44,4 +43,3 @@ Gem::Specification.new do |spec|
|
|
44
43
|
spec.add_runtime_dependency 'faraday_middleware'
|
45
44
|
spec.add_runtime_dependency 'savon', '~> 2.0'
|
46
45
|
end
|
47
|
-
# rubocop:enable Metrics/BlockLength
|
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.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Dilda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -204,8 +204,12 @@ files:
|
|
204
204
|
- bin/setup
|
205
205
|
- docker-compose.yml
|
206
206
|
- lib/varanus.rb
|
207
|
+
- lib/varanus/dcv.rb
|
208
|
+
- lib/varanus/domain.rb
|
207
209
|
- lib/varanus/error.rb
|
210
|
+
- lib/varanus/organization.rb
|
208
211
|
- lib/varanus/reports.rb
|
212
|
+
- lib/varanus/rest_resource.rb
|
209
213
|
- lib/varanus/ssl.rb
|
210
214
|
- lib/varanus/ssl/csr.rb
|
211
215
|
- lib/varanus/version.rb
|
@@ -222,15 +226,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
222
226
|
requirements:
|
223
227
|
- - ">="
|
224
228
|
- !ruby/object:Gem::Version
|
225
|
-
version: 2.
|
229
|
+
version: 2.5.0
|
226
230
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
227
231
|
requirements:
|
228
232
|
- - ">="
|
229
233
|
- !ruby/object:Gem::Version
|
230
234
|
version: '0'
|
231
235
|
requirements: []
|
232
|
-
|
233
|
-
rubygems_version: 2.7.8
|
236
|
+
rubygems_version: 3.0.3
|
234
237
|
signing_key:
|
235
238
|
specification_version: 4
|
236
239
|
summary: Interface for Sectigo's (formerly Comodo CA) API.
|