class Acmesmith::ChallengeResponders::Verisign
Public Class Methods
new(config)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 17 def initialize(config) @config = config @ttl = @config.has_key?(:ttl) ? @config[:ttl] : 3600 @timeout = 2 begin @token = @config.fetch(:token) @account_id = @config.fetch(:account_id) rescue warn "ERROR :: Please verify that you add your Verisign account 'Token' and 'ID' to the config file." exit 1 end end
Public Instance Methods
cleanup(domain, challenge)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 43 def cleanup(domain, challenge) @zone = find_zone(domain) unless @zone warn "ERROR :: Domain '#{domain}' is not configured in Verisign." exit 1 end @fqdn = canonicalize(domain, challenge) delete_rr(challenge) wait_for_sync_by_api(challenge, false) end
respond(domain, challenge)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 30 def respond(domain, challenge) @zone = find_zone(domain) unless @zone warn "ERROR :: Domain '#{domain}' is not configured in Verisign." exit 1 end @fqdn = canonicalize(domain, challenge) create_rr(challenge) wait_for_sync_by_api(challenge) wait_for_sync_by_dns(challenge) end
support?(type)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 13 def support?(type) type == 'dns-01' end
Private Instance Methods
add_slash(string)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 221 def add_slash(string) string[0] != "/" ? string.prepend("/") : string end
canonicalize(domain, challenge)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 225 def canonicalize(domain, challenge) "#{challenge.record_name}.#{domain}.".gsub(/\.{2,}/, '.') end
create_rr(challenge)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 130 def create_rr(challenge) begin data = { "owner" => "#{@fqdn}", "type" => challenge.record_type, "rdata" => "#{challenge.record_content}", "ttl" => @ttl, "comments" => "Created by acmesmith-verisign" } params = {:path => "/zones/#{@zone}/rr", :method => "POST", :data => data} query!(params) rescue => e warn "ERROR :: Failed to create record: #{@fqdn} zone: #{@zone}. error: #{e}" exit 3 end end
delete_rr(challenge)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 150 def delete_rr(challenge) records = get_rr(challenge) raise "Failed to delete record. Cannot locate record ID number." if records.empty? begin record = find_record(records, challenge) rec_id = record[1] params = {:path => "/zones/#{@zone}/rr/#{rec_id}", :method => "DELETE", :data => {"comments"=>"Deleted by acmesmith-verisign"}} query!(params) rescue => e warn "ERROR :: Failed to delete record: #{@fqdn} ID: #{rec_id}. zone: #{@zone}. error: #{e}" exit 3 end end
find_record(array, challenge)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 237 def find_record(array, challenge) if array array.map! {|r| [r["rdata"].gsub(/"/, ""), r["resource_record_id"]]} return array.select {|r| r.include?("#{challenge.record_content}")}.flatten end return [] end
find_zone(zone)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 233 def find_zone(zone) get_zones.select {|z| zone[z] }.first end
get_rr(challenge)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 116 def get_rr(challenge) begin type = challenge.record_type params = {:path => "/zones/#{@zone}/rrset/#{@fqdn}/#{type}"} query!(params) rescue => e warn "ERROR :: Failed to get record: #{@fqdn}. error: #{e}" exit 3 end end
get_zones()
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 229 def get_zones() @zones ||= query!({ :path => "/zones" }).map {|zone| zone["zone_name"]} end
query!(options = {})
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 57 def query!(options = {}) defaults = { :method => "GET"} options = defaults.merge(options) method = options[:method].downcase begin path = "#{@@verisign_rest_url}#{@account_id}#{add_slash(options.fetch(:path))}" data = options.fetch(:data).to_json unless method == "get" rescue => e warn "ERROR :: Please verify that you used all mandatory params: ':path'" exit 1 end params = { :method => method.to_sym, :url => path, :timeout => @timeout, :open_timeout => @timeout, :headers => { Authorization: "Token #{@token}", content_type: :json, accept: :json } } begin if method == "get" resp = RestClient::Request.execute(params) else params[:payload] = data resp = RestClient::Request.execute(params) end if method == "get" body = JSON.parse(resp.body) if body.has_key?("total_count") && body["total_count"] > 0 body.each do | _key, val | if val.kind_of?(Array) return val end end # each body end # if body.has_key? end # if method rescue RestClient::ExceptionWithResponse => e if e.http_code.to_s[/[4][0-9][0-9]/] body = JSON.parse(e.response.body) err_msg = body ? body['error_messages'] : nil end warn "Verisign :: Failed to query Verisign and parse response with error: #{e}. err_msg: #{err_msg}" exit 2 rescue => e warn "Verisign :: Failed to query Verisign and parse response with error: #{e}." exit 2 end # rescue end
wait_for_sync_by_api(challenge, for_create = true)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 167 def wait_for_sync_by_api(challenge, for_create = true) puts " * API Check :: Checking if record found using Verisign API --> record: #{@fqdn} expected value: #{challenge.record_content}" record = find_record(get_rr(challenge), challenge) if for_create while record == [] puts " * Record creation still in process. waiting 3 seconds." sleep 3 record = find_record(get_rr(challenge), challenge) end puts " * Confirm new record creation using API!" return true else while record != [] puts " * Record deletion still in process. waiting 3 seconds" sleep 3 record = find_record(get_rr(challenge), challenge) end puts " * Confirm record deletion using API!" return true end # if for_create end
wait_for_sync_by_dns(challenge)
click to toggle source
# File lib/acmesmith/challenge_responders/verisign.rb, line 195 def wait_for_sync_by_dns(challenge) value = challenge.record_content puts " * DNS CHeck :: Checking if record found using DNS query --> record: #{@fqdn} expected value: #{challenge.record_content}" resolv = Resolv::DNS.new() nameservers = resolv.getresources(@zone, Resolv::DNS::Resource::IN::NS).map {|ns| Resolv.getaddresses(ns.name.to_s).first} Resolv::DNS.open(:nameserver => nameservers) do | dns | dns.timeouts = @timeout loop do resolv_value = dns.getresources(@fqdn, Resolv::DNS::Resource::IN::TXT).map(&:data).first if resolv_value == value puts " * Success - Value found and it is as expected. value: #{resolv_value}" sleep 1 break else puts " * Waiting - Value still does not match the expected result. current value: #{resolv_value}" sleep 3 end end # loop end # Resolv::DNS end