anchor-pki 0.6.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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