acme_nsupdate 0.2.1 → 0.3.0

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
  SHA1:
3
- metadata.gz: 32d57c19eaf5a6c23f23af08da0f6aa8f4089855
4
- data.tar.gz: 8cacaab5401445f956efa5b001a339559f64b14d
3
+ metadata.gz: 7e22b3776fb2331b29ccdbded623176832232282
4
+ data.tar.gz: 395303634131286629fd3092f102651d4e4901da
5
5
  SHA512:
6
- metadata.gz: c7ba48ba36dfd57d13726be92ff5a40028626118442dd57dc9e7659ab81207be33f9d8f2713c41e2f6d7ae0a250820dc9e3c87aed6312a9a2e391444ca83ee18
7
- data.tar.gz: 6c0e2cc6bae8556affad2e617c9a2ea4ec9f0d463c2a5b3c11be1d24e1b56f9ad3d2e129c665e68ea036e8a3c798c42c2ac9644d2baa024b944c9e9beb330b06
6
+ metadata.gz: b227c653a1414547d8317d4ada1091cbdf36c71f79be39ac4de08a6406a2b06bd0ea89f73a52076b9a7eeabadb34286c46b609f953c2d2cc4a384a5c63c5cffc
7
+ data.tar.gz: 8df03352e20f02af82cc2ccf2ac8fe9b1997976e10ddc86160e7a14fbc9ed601c0d92431f15e08953f2d318ad8f8e86be246f718b3802bda2971ba824a209f13
@@ -1,3 +1,5 @@
1
+ require "resolv"
2
+
1
3
  require "acme_nsupdate/strategy"
2
4
 
3
5
  module AcmeNsupdate
@@ -12,23 +14,24 @@ module AcmeNsupdate
12
14
  end
13
15
 
14
16
  def publish_challenges
15
- @client.logger.debug "Publishing challenges for #{@client.options[:domains].join(", ")}"
16
-
17
- challenges = @client.options[:domains].map {|domain|
18
- nsupdate = @client.build_nsupdate
19
-
20
- authorization = @client.client.authorize domain: domain
17
+ challenges = map_authorizations {|domain, authorization|
21
18
  challenge = authorization.dns01
22
19
  abort "Challenge dns-01 not supported by the given ACME server" unless challenge
20
+
21
+ nsupdate = @client.build_nsupdate
23
22
  nsupdate.del(*record(domain, challenge, true)) unless @client.options[:keep]
24
23
  nsupdate.add(*record(domain, challenge), @client.options[:txt_ttl])
25
24
  nsupdate.send
26
25
 
27
- [domain, challenge]
28
- }.to_h
26
+ challenge
27
+ }
29
28
 
30
- @client.logger.info "Waiting 120 seconds for the DNS updates to go live"
31
- sleep 120 # We wait some time to give the slaves time to update
29
+ unless challenges.empty?
30
+ @client.logger.info "Waiting up to 120 seconds for the DNS updates to go live"
31
+ unless verify_live_challenges(@client.options[:master], challenges)
32
+ raise AcmeNsupdate::Client::Error, "DNS challenges didn't appear on all nameservers within 120 seconds"
33
+ end
34
+ end
32
35
 
33
36
  challenges
34
37
  end
@@ -44,6 +47,58 @@ module AcmeNsupdate
44
47
 
45
48
  private
46
49
 
50
+ def verify_live_challenges(primary, challenges, timeout=120)
51
+ waited = 0
52
+ public_nameservers(primary, challenges.first.first).all? {|nameserver|
53
+ @client.logger.debug "Verifying DNS challenges are present on #{nameserver}"
54
+ challenges.all? {|domain, challenge|
55
+ name, type, content = record(domain, challenge)
56
+ records = query(nameserver, name, type).map(&:strings).flatten.map {|content| %("#{content}") }
57
+ @client.logger.debug "Got #{records.size} TXT records for #{name}: #{records.map(&:inspect).join(", ")}"
58
+ if records.include? content
59
+ true
60
+ elsif waited == timeout
61
+ @client.logger.error "None matched, timeout reached, aborting"
62
+ return false
63
+ else
64
+ @client.logger.debug "None matched, pausing for 5 seconds, already waited #{waited} seconds"
65
+ sleep 5
66
+ waited += 5
67
+ redo
68
+ end
69
+ }
70
+ }
71
+ end
72
+
73
+ def public_nameservers(primary, name)
74
+ # We have to hack into this because it gives us no way to fetch the SOA on a NXDOMAIN
75
+ authority = nil
76
+ Resolv::DNS.open(nameserver: [primary], search: [], ndots: 1) do |dns|
77
+ dns.lazy_initialize
78
+ message = Resolv::DNS::Message.new
79
+ message.rd = 1
80
+ message.add_question(name, Resolv::DNS::Resource::IN::SOA)
81
+ requester = dns.make_udp_requester
82
+
83
+ begin
84
+ sender = requester.sender(message, name, primary, 53)
85
+ reply, _ = requester.request(sender, 10)
86
+ authority = reply.authority.first.first.to_s
87
+ ensure
88
+ requester.close
89
+ end
90
+ end
91
+
92
+ return [] unless authority
93
+ query(primary, authority, :NS).map {|record| record.name.to_s }.uniq
94
+ end
95
+
96
+ def query(nameserver, name, qtype)
97
+ Resolv::DNS.open(nameserver: [nameserver], search: [], ndots: 1) do |dns|
98
+ return dns.getresources(name, Resolv::DNS::Resource::IN.const_get(qtype))
99
+ end
100
+ end
101
+
47
102
  def record domain, challenge, nodata=false
48
103
  ["#{challenge.record_name}.#{domain}", challenge.record_type].tap do |record|
49
104
  record << %("#{challenge.record_content}") unless nodata
@@ -14,17 +14,17 @@ module AcmeNsupdate
14
14
  end
15
15
 
16
16
  def publish_challenges
17
- @client.logger.debug "Publishing challenges for #{@client.options[:domains].join(", ")}"
18
- @client.options[:domains].map {|domain|
19
- authorization = @client.client.authorize domain: domain
17
+ map_authoriations {|domain, authorization|
20
18
  challenge = authorization.http01
21
19
  abort "Challenge http-01 not supported by this ACME server" unless challenge
20
+
22
21
  path = path challenge
23
22
  @client.logger.debug "Writing #{path} for #{domain}"
24
23
  FileUtils.mkdir_p File.dirname path
25
24
  File.write path, challenge.file_content
25
+
26
26
  [domain, challenge]
27
- }.to_h
27
+ }.compact.to_h
28
28
  end
29
29
 
30
30
  def cleanup challenges
@@ -21,8 +21,29 @@ module AcmeNsupdate
21
21
  end
22
22
  end
23
23
 
24
+
24
25
  private
25
26
 
27
+ def map_authorizations
28
+ @client.logger.debug "Publishing challenges for #{@client.options[:domains].join(", ")}"
29
+
30
+ challenges = @client.options[:domains].map {|domain|
31
+ authorization = @client.client.authorize domain: domain
32
+ if authorization.status == "valid"
33
+ @client.logger.debug("Skipping challenge for #{domain}, already valid.")
34
+ next
35
+ end
36
+
37
+ challenge = yield domain, authorization
38
+ unless challenge
39
+ @client.logger.debug("Skipping challenge for #{domain}, not solvable.")
40
+ next
41
+ end
42
+
43
+ [domain, challenge]
44
+ }.compact.to_h
45
+ end
46
+
26
47
  def wait_for_verification challenges
27
48
  @client.logger.debug("Requesting verification")
28
49
  challenges.each_value(&:request_verification)
@@ -1,3 +1,3 @@
1
1
  module AcmeNsupdate
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acme_nsupdate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonne Haß
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-10 00:00:00.000000000 Z
11
+ date: 2016-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slop