anchor-pki 0.6.3 → 0.7.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.
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Anchor
4
- module AutoCert
5
- class PolicyCheck
6
- # Check the identifier by strict hostname name comparison
7
- #
8
- # Reference: http://www.faqs.org/rfcs/rfc2396.html
9
- #
10
- class ForHostname < PolicyCheck
11
- ALPHA = '[a-zA-Z]'
12
- ALPHA_NUMERIC = '[a-zA-Z0-9]'
13
- ALPHA_NUMERIC_HYPHEN = '[-a-zA-Z0-9]'
14
- DOMAIN_LABEL = "#{ALPHA_NUMERIC}#{ALPHA_NUMERIC_HYPHEN}*#{ALPHA_NUMERIC}"
15
- TOP_LEVEL_DOMAIN = "#{ALPHA}#{ALPHA_NUMERIC_HYPHEN}*#{ALPHA_NUMERIC}"
16
-
17
- REGEX = /
18
- \A
19
- (?<sub>(#{DOMAIN_LABEL}\.)+)
20
- (?<tld>#{TOP_LEVEL_DOMAIN})
21
- \z
22
- /ix.freeze
23
-
24
- def self.handles?(description)
25
- description.is_a?(String) && description.match?(REGEX)
26
- end
27
-
28
- def initialize(description)
29
- super
30
- @hostname = description.downcase
31
- end
32
-
33
- # case insensitive comparison
34
- def allow?(name)
35
- name.is_a?(String) && (name.downcase == @hostname)
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'ipaddr'
4
- module Anchor
5
- module AutoCert
6
- class PolicyCheck
7
- #
8
- # A PolicyCheck that compares the given IP address to an ipaddress
9
- # or subnet
10
- #
11
- # The description for an IPAddr policy check can be anything that is
12
- # parsed by the ruby IPAddr.new() method. Generally this is something in
13
- # the format an ipv4 address, an ipv6 address, or CIDR notation.
14
- #
15
- # - "192.168.42.1"
16
- # - "192.168.42.0/24"
17
- # - "3ffe:505:2::1"
18
- # - "2001:db8::/32"
19
- #
20
- class ForIPAddr < PolicyCheck
21
- def self.handles?(description)
22
- return true if description.is_a?(IPAddr)
23
-
24
- begin
25
- IPAddr.new(description)
26
- true
27
- rescue IPAddr::Error
28
- false
29
- end
30
- end
31
-
32
- def initialize(description)
33
- super
34
-
35
- @ipaddr = if description.is_a?(IPAddr)
36
- description
37
- else
38
- IPAddr.new(description)
39
- end
40
- end
41
-
42
- def allow?(name)
43
- @ipaddr.include?(name)
44
- end
45
- end
46
- end
47
- end
48
- end
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Anchor
4
- module AutoCert
5
- class PolicyCheck
6
- # Check that the identifier is allowed by wildcard hostname matching
7
- #
8
- # This does the same as the ForHostname check, but allows for an arbitrary
9
- # prefixes, although the prefix itself also needs to match appropriate
10
- # domain name rules.
11
- #
12
- # The description for a wildcard hostname check MUST be a string that starts
13
- # with `*.` followed by a valid domainname (which matches the ForHostname
14
- # check)
15
- #
16
- #
17
- class ForWildcardHostname < PolicyCheck
18
- DOMAIN_LABEL_REGEX = /\A#{ForHostname::DOMAIN_LABEL}*\z/i.freeze
19
- SPLAT = '*'
20
-
21
- def self.handles?(description)
22
- return false unless description.is_a?(String)
23
-
24
- parts = description.split('.')
25
- return false unless parts[0] == SPLAT
26
-
27
- suffix = parts[1..-1].join('.')
28
- # reuse the hostname check here
29
- ForHostname.handles?(suffix)
30
- end
31
-
32
- def initialize(description)
33
- super
34
- @parts = description.split('.')
35
- @wildcard = @parts.shift # assumed SPLAT
36
- @suffix = @parts.join('.').downcase
37
- end
38
-
39
- # An explicit '*.rest.of' is an allowable hostname for this check, even
40
- # though it is not a valid domain name
41
- #
42
- def allow?(hostname)
43
- return false unless hostname.is_a?(String)
44
-
45
- parts = hostname.split('.')
46
- prefix = parts.shift
47
-
48
- return false unless (prefix == SPLAT) || DOMAIN_LABEL_REGEX.match?(prefix)
49
-
50
- domain = parts.join('.').downcase
51
-
52
- (domain == @suffix)
53
- end
54
- end
55
- end
56
- end
57
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Anchor
4
- module AutoCert
5
- # Base class for PolicyCheck classes, these are utility classes used by the
6
- # IdentifierPolicy class.
7
- #
8
- # The .handles? method is used to determine if an instance of this class
9
- # could be created from the given description.
10
- #
11
- # Then the #allow? method is used to determine if the given identifier is allowed
12
- # and the #deny? method is used to determine if the given identifier is denied.
13
- #
14
- class PolicyCheck
15
- def self.handles?(description)
16
- raise NotImplementedError, "#{self.class} must implement .handles?(description)"
17
- end
18
-
19
- attr_reader :policy_description
20
-
21
- def initialize(description)
22
- @policy_description = description
23
- end
24
-
25
- def deny?(identifier)
26
- !allow?(identifier)
27
- end
28
-
29
- def allow?(identifier)
30
- raise NotImplementedError, "#{self.class} must implement #allow?(identifier)"
31
- end
32
- end
33
- end
34
- end
35
- require_relative 'policy_check/for_ipaddr'
36
- require_relative 'policy_check/for_hostname'
37
- require_relative 'policy_check/for_wildcard_hostname'
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Anchor
4
- module AutoCert
5
- # A global registry for storing AutoCert::Configuration objects
6
- class Registry
7
- @_registry = {}
8
- @_mutex = Mutex.new
9
-
10
- def self.store(name, configuration)
11
- @_mutex.synchronize do
12
- @_registry.store(name.to_s, configuration)
13
- end
14
- end
15
-
16
- def self.fetch(name)
17
- @_mutex.synchronize do
18
- @_registry.fetch(name.to_s)
19
- end
20
- end
21
-
22
- def self.key?(name)
23
- @_mutex.synchronize do
24
- @_registry.key?(name.to_s)
25
- end
26
- end
27
-
28
- def self.delete(name)
29
- @_mutex.synchronize do
30
- @_registry.delete(name.to_s)
31
- end
32
- end
33
-
34
- # helpers for creating an AutoCert::Manager instance from registered
35
- # configuration
36
- def self.manager_for(name)
37
- manager_for!(name)
38
- rescue KeyError
39
- nil
40
- end
41
-
42
- # helpers for creating an AutoCert::Manager instance from registered
43
- # configuration - raises KeyError if the named configuration does not
44
- # exist
45
- def self.manager_for!(name)
46
- configuration = fetch(name)
47
- AutoCert::Manager.new(configuration: configuration)
48
- end
49
-
50
- def self.default_configuration
51
- fetch(:default)
52
- rescue KeyError
53
- default = AutoCert::Configuration.new
54
- store(:default, default)
55
- default
56
- end
57
-
58
- def self.default_manager
59
- manager_for(:default)
60
- end
61
- end
62
- end
63
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Anchor
4
- module AutoCert
5
- # RenewalBusyWait is a class that will loop to check if a certificate needs to
6
- # to be renewed, and if it does, return
7
- #
8
- # Generally this class should be used inside its own thread as it will sleep
9
- # and loop until the pem file is able to be renewed.
10
- #
11
- # Every 'check_every' interval it will check if the certificate needs to be
12
- # renewed. If it does, the loop will end and `wait_for_it` will return. If
13
- # it does not need renewal, the block will be called, and if the result of
14
- # the block is falsy, the loop will exit early
15
- #
16
- class RenewalBusyWait
17
- ONE_HOUR = 60 * 60
18
-
19
- def self.wait_for_it(manager:, managed_certificate:, check_every: ONE_HOUR, &keep_going)
20
- waiter = new(manager: manager, managed_certificate: managed_certificate, check_every: check_every)
21
- waiter.wait_for_it(&keep_going)
22
- end
23
-
24
- def initialize(manager:, managed_certificate:, check_every: ONE_HOUR)
25
- @manager = manager
26
- @managed_certificate = managed_certificate
27
- @check_every = check_every
28
- end
29
-
30
- def wait_for_it
31
- loop do
32
- break if @manager.needs_renewal?(cert: @managed_certificate)
33
- break unless yield
34
-
35
- sleep @check_every
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Anchor
4
- module AutoCert
5
- # Any class that implements the following interface can be used as a
6
- # Terms of Service Acceptor. The interface is the single method `#accept?`
7
- # which is handed the terms of service URI as a String.
8
- module TermsOfServiceAcceptor
9
- def accept?(tos_uri)
10
- raise NotImplementedError, "#{self.class} must implement #accept?(tos_uri)"
11
- end
12
-
13
- # Terms of Service Acceptor that will always match anything
14
- class Any
15
- include TermsOfServiceAcceptor
16
- def accept?(_tos_uri)
17
- true
18
- end
19
- end
20
-
21
- # Terms of Service Acceptor that matches based upon a regular expression
22
- class Regex
23
- include TermsOfServiceAcceptor
24
- def initialize(regex)
25
- @regex = regex
26
- end
27
-
28
- def accept?(tos_uri)
29
- @regex.match?(tos_uri)
30
- end
31
- end
32
- end
33
- end
34
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'pstore'
4
- require 'tempfile'
5
-
6
- module Anchor
7
- # DiskStore is a simple key/value store that persists to disk using PStore.
8
- #
9
- class DiskStore
10
- def initialize(dir: nil, basename: 'anchor-disk-store')
11
- @dir = dir || Dir.mktmpdir
12
- @basename = basename
13
- @path = File.join(@dir, @basename)
14
- @pstore = PStore.new(@path, true)
15
- end
16
-
17
- def [](key)
18
- data = nil
19
- @pstore.transaction do
20
- data = @pstore[key]
21
- end
22
- data
23
- end
24
-
25
- def []=(key, value)
26
- @pstore.transaction do
27
- @pstore[key] = value
28
- end
29
- end
30
- end
31
- end