diff --git a/app/jobs/regenerate_subzone_whoises_job.rb b/app/jobs/regenerate_subzone_whoises_job.rb new file mode 100644 index 000000000..280fa4088 --- /dev/null +++ b/app/jobs/regenerate_subzone_whoises_job.rb @@ -0,0 +1,11 @@ +class RegenerateSubzoneWhoisesJob < Que::Job + def run + subzones = DNS::Zone.all + + subzones.each do |zone| + next unless zone.subzone? + + UpdateWhoisRecordJob.enqueue zone.origin, 'zone' + end + end +end diff --git a/app/jobs/update_whois_record_job.rb b/app/jobs/update_whois_record_job.rb index 16f4e0e79..2973d5a6b 100644 --- a/app/jobs/update_whois_record_job.rb +++ b/app/jobs/update_whois_record_job.rb @@ -3,15 +3,10 @@ class UpdateWhoisRecordJob < Que::Job def run(names, type) ::PaperTrail.request.whodunnit = "job - #{self.class.name} - #{type}" - klass = case type - when 'reserved' then ReservedDomain - when 'blocked' then BlockedDomain - when 'domain' then Domain - when 'disputed' then Dispute.active - end + klass = determine_class(type) Array(names).each do |name| - record = klass.find_by(name: name) + record = find_record(klass, name) if record send "update_#{type}", record else @@ -20,6 +15,20 @@ class UpdateWhoisRecordJob < Que::Job end end + def find_record(klass, name) + klass == DNS::Zone ? klass.find_by(origin: name) : klass.find_by(name: name) + end + + def determine_class(type) + case type + when 'reserved' then ReservedDomain + when 'blocked' then BlockedDomain + when 'domain' then Domain + when 'disputed' then Dispute.active + when 'zone' then DNS::Zone + end + end + def update_domain(domain) domain.whois_record ? domain.whois_record.save : domain.create_whois_record end @@ -36,6 +45,10 @@ class UpdateWhoisRecordJob < Que::Job update_reserved(record) end + def update_zone(record) + update_reserved(record) + end + # 1. deleting own # 2. trying to regenerate reserved in order domain is still in the list def delete_domain(name) @@ -60,6 +73,11 @@ class UpdateWhoisRecordJob < Que::Job remove_status_from_whois(domain_name: name, domain_status: 'disputed') end + def delete_zone(name) + WhoisRecord.where(name: name).destroy_all + Whois::Record.where(name: name).destroy_all + end + def remove_status_from_whois(domain_name:, domain_status:) Whois::Record.where(name: domain_name).each do |r| r.json['status'] = r.json['status'].delete_if { |status| status == domain_status } diff --git a/app/models/concerns/zone/whois_queryable.rb b/app/models/concerns/zone/whois_queryable.rb new file mode 100644 index 000000000..2c453dbef --- /dev/null +++ b/app/models/concerns/zone/whois_queryable.rb @@ -0,0 +1,72 @@ +module Concerns + module Zone + module WhoisQueryable + extend ActiveSupport::Concern + + included do + after_save :update_whois_record, if: :subzone? + after_destroy :update_whois_record + end + + def subzone? + origin.include? '.' + end + + def update_whois_record + UpdateWhoisRecordJob.enqueue origin, 'zone' + end + + def generate_data + wr = Whois::Record.find_or_initialize_by(name: origin) + wr.json = generate_json + wr.save + end + + def generate_json + data = {}.with_indifferent_access + [domain_vars, registrar_vars, registrant_vars].each do |h| + data.merge!(h) + end + + data + end + + def domain_vars + { disclaimer: Setting.registry_whois_disclaimer, name: origin, + registered: created_at.try(:to_s, :iso8601), status: ['ok (paid and in zone)'], + changed: updated_at.try(:to_s, :iso8601), email: Setting.registry_email, + admin_contacts: [contact_vars], tech_contacts: [contact_vars], + nameservers: nameserver_vars } + end + + def registrar_vars + { registrar: Setting.registry_juridical_name, registrar_website: Setting.registry_url, + registrar_phone: Setting.registry_phone } + end + + def registrant_vars + { registrant: Setting.registry_juridical_name, registrant_reg_no: Setting.registry_reg_no, + registrant_ident_country_code: Setting.registry_country_code, registrant_kind: 'org', + registrant_disclosed_attributes: %w[name email] } + end + + def contact_vars + { name: Setting.registry_invoice_contact, email: Setting.registry_email, + disclosed_attributes: %w[name email] } + end + + def nameserver_vars + vars = [] + return vars unless ns_records + + parsed_ns = ns_records.gsub("\r", '').gsub("\n", '') + parsed_ns.split("#{origin}. IN NS ").each do |ns| + ns.delete_suffix! '.' + vars << ns if ns.match? Nameserver::HOSTNAME_REGEXP + end + + vars + end + end + end +end diff --git a/app/models/dns/zone.rb b/app/models/dns/zone.rb index a641c4e49..31749d952 100644 --- a/app/models/dns/zone.rb +++ b/app/models/dns/zone.rb @@ -1,8 +1,11 @@ +# frozen_string_literal: true + module DNS class Zone < ApplicationRecord validates :origin, :ttl, :refresh, :retry, :expire, :minimum_ttl, :email, :master_nameserver, presence: true validates :ttl, :refresh, :retry, :expire, :minimum_ttl, numericality: { only_integer: true } validates :origin, uniqueness: true + include Concerns::Zone::WhoisQueryable before_destroy do throw(:abort) if used? diff --git a/test/jobs/regeneate_subzone_whoises_job_test.rb b/test/jobs/regeneate_subzone_whoises_job_test.rb new file mode 100644 index 000000000..745c2392c --- /dev/null +++ b/test/jobs/regeneate_subzone_whoises_job_test.rb @@ -0,0 +1,18 @@ +require 'test_helper' + +class RegenerateSubzoneWhoisesJobTest < ActiveSupport::TestCase + def test_regenerates_whois_data_only_for_subzones + subzone = dns_zones(:one).dup + subzone.origin = 'subzone.test' + subzone.save + + Whois::Record.where(name: subzone.origin).destroy_all + Whois::Record.where(name: dns_zones(:one)).destroy_all + assert_nil Whois::Record.find_by(name: subzone.origin) + assert_nil Whois::Record.find_by(name: dns_zones(:one).origin) + + RegenerateSubzoneWhoisesJob.run + assert Whois::Record.find_by(name: subzone.origin) + assert_nil Whois::Record.find_by(name: dns_zones(:one).origin) + end +end diff --git a/test/models/dns/zone_test.rb b/test/models/dns/zone_test.rb index c18f9592a..fab4c6355 100644 --- a/test/models/dns/zone_test.rb +++ b/test/models/dns/zone_test.rb @@ -124,6 +124,60 @@ class DNS::ZoneTest < ActiveSupport::TestCase assert zone.invalid? end + def test_determines_if_subzone + zone = valid_zone + zone.update(origin: 'pri.ee') + assert zone.subzone? + end + + def test_updates_whois_after_update + subzone = dns_zones(:one).dup + + subzone.origin = 'sub.zone' + subzone.save + + whois_record = Whois::Record.find_by(name: subzone.origin) + assert whois_record.present? + end + + def test_has_setting_info_as_contacts_for_subzones + subzone = dns_zones(:one).dup + + subzone.origin = 'sub.zone' + subzone.save + + whois_record = Whois::Record.find_by(name: subzone.origin) + assert whois_record.present? + + assert_equal Setting.registry_whois_disclaimer, whois_record.json['disclaimer'] + assert_equal Setting.registry_email, whois_record.json['email'] + assert_equal Setting.registry_juridical_name, whois_record.json['registrar'] + assert_equal Setting.registry_url, whois_record.json['registrar_website'] + assert_equal Setting.registry_phone, whois_record.json['registrar_phone'] + + assert_equal Setting.registry_juridical_name, whois_record.json['registrant'] + assert_equal Setting.registry_reg_no, whois_record.json['registrant_reg_no'] + assert_equal Setting.registry_country_code, whois_record.json['registrant_ident_country_code'] + + contact = { name: Setting.registry_invoice_contact, email: Setting.registry_email, + disclosed_attributes: %w[name email] }.with_indifferent_access + + assert_equal contact, whois_record.json['admin_contacts'][0] + assert_equal contact, whois_record.json['tech_contacts'][0] + end + + def test_deletes_whois_record_after_destroy + subzone = dns_zones(:one).dup + + subzone.origin = 'sub.zone' + subzone.save + + assert Whois::Record.find_by(name: subzone.origin).present? + + subzone.destroy + assert_nil Whois::Record.find_by(name: subzone.origin) + end + private def valid_zone