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 +4 -4
- data/lib/acme_nsupdate/strategies/dns01.rb +65 -10
- data/lib/acme_nsupdate/strategies/http01.rb +4 -4
- data/lib/acme_nsupdate/strategy.rb +21 -0
- data/lib/acme_nsupdate/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e22b3776fb2331b29ccdbded623176832232282
|
4
|
+
data.tar.gz: 395303634131286629fd3092f102651d4e4901da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
28
|
-
}
|
26
|
+
challenge
|
27
|
+
}
|
29
28
|
|
30
|
-
|
31
|
-
|
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
|
-
|
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)
|
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.
|
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-
|
11
|
+
date: 2016-08-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: slop
|