diff --git a/app/models/domain.rb b/app/models/domain.rb index edc8e02cc..1bbecc62d 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -141,7 +141,7 @@ class Domain < ActiveRecord::Base false end - validates :nameservers, object_count: { + validates :nameservers, domain_nameserver: { min: -> { Setting.ns_min_count }, max: -> { Setting.ns_max_count } } @@ -692,6 +692,11 @@ class Domain < ActiveRecord::Base p_d = statuses.include?(DomainStatus::PENDING_DELETE) s_h = (statuses & [DomainStatus::SERVER_MANUAL_INZONE, DomainStatus::SERVER_HOLD]).empty? statuses << DomainStatus::SERVER_HOLD if p_d && s_h + + if !self.class.nameserver_required? + statuses << DomainStatus::INACTIVE if nameservers.empty? + statuses.delete(DomainStatus::INACTIVE) if nameservers.size >= Setting.ns_min_count + end end # rubocop: enable Metrics/CyclomaticComplexity # rubocop: enable Metrics/PerceivedComplexity diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 155d70c18..6a2edf5ed 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -71,12 +71,6 @@ class Epp::Domain < Domain [:base, :required_parameter_missing_reserved] ], '2004' => [ # Parameter value range error - [:nameservers, :out_of_range, - { - min: Setting.ns_min_count, - max: Setting.ns_max_count - } - ], [:dnskeys, :out_of_range, { min: Setting.dnskeys_min_count, @@ -124,7 +118,13 @@ class Epp::Domain < Domain [:registrant, :cannot_be_missing] ], '2308' => [ - [:base, :domain_name_blocked, { value: { obj: 'name', val: name_dirty } }] + [:base, :domain_name_blocked, { value: { obj: 'name', val: name_dirty } }], + [:nameservers, :out_of_range, + { + min: Setting.ns_min_count, + max: Setting.ns_max_count + } + ], ] } end diff --git a/app/validators/domain_nameserver_validator.rb b/app/validators/domain_nameserver_validator.rb new file mode 100644 index 000000000..b9a607bb9 --- /dev/null +++ b/app/validators/domain_nameserver_validator.rb @@ -0,0 +1,12 @@ +class DomainNameserverValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + return true if !Domain.nameserver_required? && value.empty? + + min, max = options[:min].call, options[:max].call + values = value.reject(&:marked_for_destruction?) + + return if values.size.between?(min, max) + association = options[:association] || attribute + record.errors.add(association, :out_of_range, { min: min, max: max }) + end +end diff --git a/config/locales/en.yml b/config/locales/en.yml index 92158b6fd..8e4d26b9b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -97,7 +97,7 @@ en: out_of_range: 'Tech contacts count must be between %{min}-%{max}' nameservers: invalid: 'Nameservers are invalid' - out_of_range: 'Nameservers count must be between %{min}-%{max}' + out_of_range: Data management policy violation; Nameserver count must be between %{min}-%{max} for active domains not_found: 'Nameserver was not found' taken: 'Nameserver already exists on this domain' less_than_or_equal_to: 'Nameservers count must be less than or equal to %{count}' diff --git a/spec/factories/domain.rb b/spec/factories/domain.rb index 5a396362d..534670ce0 100644 --- a/spec/factories/domain.rb +++ b/spec/factories/domain.rb @@ -7,7 +7,6 @@ FactoryGirl.define do registrant after :build do |domain| - domain.nameservers << FactoryGirl.build_pair(:nameserver) domain.admin_domain_contacts << FactoryGirl.build(:admin_domain_contact) domain.tech_domain_contacts << FactoryGirl.build(:tech_domain_contact) end diff --git a/spec/models/domain_spec.rb b/spec/models/domain_spec.rb index 8b1554b68..555cf48e1 100644 --- a/spec/models/domain_spec.rb +++ b/spec/models/domain_spec.rb @@ -37,7 +37,6 @@ RSpec.describe Domain do @domain.valid? @domain.errors.full_messages.should match_array([ "Admin domain contacts Admin contacts count must be between 1-10", - "Nameservers Nameservers count must be between 2-11", "Period Period is not a number", "Registrant Registrant is missing", "Registrar Registrar is missing" @@ -704,6 +703,71 @@ RSpec.describe Domain, db: false do it { is_expected.to alias_attribute(:force_delete_time, :force_delete_at) } it { is_expected.to alias_attribute(:outzone_time, :outzone_at) } + describe 'nameserver validation', db: true do + let(:domain) { described_class.new } + + it 'rejects less than min' do + Setting.ns_min_count = 2 + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.validate + expect(domain.errors).to have_key(:nameservers) + end + + it 'rejects more than max' do + Setting.ns_min_count = 1 + Setting.ns_max_count = 1 + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.validate + expect(domain.errors).to have_key(:nameservers) + end + + it 'accepts min' do + Setting.ns_min_count = 1 + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.validate + expect(domain.errors).to_not have_key(:nameservers) + end + + it 'accepts max' do + Setting.ns_min_count = 1 + Setting.ns_max_count = 2 + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.validate + expect(domain.errors).to_not have_key(:nameservers) + end + + context 'when nameserver is optional' do + before :example do + allow(Domain).to receive(:nameserver_required?).and_return(false) + end + + it 'rejects less than min' do + Setting.ns_min_count = 2 + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.validate + expect(domain.errors).to have_key(:nameservers) + end + + it 'accepts absent' do + domain.validate + expect(domain.errors).to_not have_key(:nameservers) + end + end + + context 'when nameserver is required' do + before :example do + allow(Domain).to receive(:nameserver_required?).and_return(true) + end + + it 'rejects absent' do + domain.validate + expect(domain.errors).to have_key(:nameservers) + end + end + end + describe '::nameserver_required?' do before do Setting.nameserver_required = 'test' diff --git a/spec/requests/epp/domain/create_spec.rb b/spec/requests/epp/domain/create_spec.rb new file mode 100644 index 000000000..1311e4033 --- /dev/null +++ b/spec/requests/epp/domain/create_spec.rb @@ -0,0 +1,198 @@ +require 'rails_helper' + +RSpec.describe 'EPP domain:create' do + subject(:response_xml) { Nokogiri::XML(response.body) } + subject(:response_code) { response_xml.xpath('//xmlns:result').first['code'] } + subject(:response_description) { response_xml.css('result msg').text } + + before :example do + travel_to Time.zone.parse('05.07.2010') + + registrar = create(:registrar) + user = create(:api_user_epp, registrar: registrar) + create(:account, registrar: registrar, balance: 1.0) + + create(:contact, code: 'test') + + create(:pricelist, + category: 'com', + duration: '1year', + price: 1.to_money, + operation_category: 'create', + valid_from: Time.zone.parse('05.07.2010'), + valid_to: Time.zone.parse('05.07.2010') + ) + + sign_in_to_epp_area(user: user) + end + + context 'when nameserver is optional' do + before :example do + allow(Domain).to receive(:nameserver_required?).and_return(false) + end + + context 'when minimum nameserver count is not satisfied' do + let(:request_xml) { <<-XML + + + + + + test.com + 1 + + + ns.test.com + 192.168.1.1 + + + test + test + test + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + before :example do + Setting.ns_min_count = 2 + end + + it 'returns epp code of 2308' do + post '/epp/command/create', frame: request_xml + expect(response_code).to eq('2308') + end + + it 'returns epp description' do + post '/epp/command/create', frame: request_xml + + description = 'Data management policy violation;' \ + " Nameserver count must be between #{Setting.ns_min_count}-#{Setting.ns_max_count}" \ + ' for active domains [nameservers]' + expect(response_description).to eq(description) + end + end + + context 'when nameserver is absent' do + let(:request_xml) { <<-XML + + + + + + test.com + 1 + test + test + test + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 1000' do + post '/epp/command/create', frame: request_xml + expect(response_code).to eq('1000'), "Expected EPP code of 1000, got #{response_code} (#{response_description})" + end + + it 'creates new domain' do + expect { post '/epp/command/create', frame: request_xml }.to change { Domain.count }.from(0).to(1) + end + + describe 'new domain' do + it 'has status of inactive' do + post '/epp/command/create', frame: request_xml + domain = Domain.find_by(name: 'test.com') + expect(domain.statuses).to include(DomainStatus::INACTIVE) + end + end + end + end + + context 'when nameserver is required' do + before :example do + allow(Domain).to receive(:nameserver_required?).and_return(true) + Setting.ns_min_count = 1 + end + + context 'when nameserver is present' do + let(:request_xml) { <<-XML + + + + + + test.com + 1 + + + ns.test.com + 192.168.1.1 + + + test + test + test + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 1000' do + post '/epp/command/create', frame: request_xml + expect(response_code).to eq('1000'), "Expected EPP code of 1000, got #{response_code} (#{response_description})" + end + end + + context 'when nameserver is absent' do + let(:request_xml) { <<-XML + + + + + + test.com + 1 + test + test + test + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 2003' do + post '/epp/command/create', frame: request_xml + expect(response_code).to eq('2003') + end + end + end +end diff --git a/spec/requests/epp/domain/update_spec.rb b/spec/requests/epp/domain/update_spec.rb new file mode 100644 index 000000000..6a31562f9 --- /dev/null +++ b/spec/requests/epp/domain/update_spec.rb @@ -0,0 +1,193 @@ +require 'rails_helper' + +RSpec.describe 'EPP domain:update' do + let!(:domain) { create(:domain, name: 'test.com') } + subject(:response_xml) { Nokogiri::XML(response.body) } + subject(:response_code) { response_xml.xpath('//xmlns:result').first['code'] } + subject(:response_description) { response_xml.css('result msg').text } + + before :example do + sign_in_to_epp_area + + allow(Domain).to receive(:nameserver_required?).and_return(false) + Setting.ns_min_count = 2 + Setting.ns_max_count = 3 + end + + describe 'nameserver add' do + context 'when nameserver count is less than minimum' do + let(:request_xml) { <<-XML + + + + + + test.com + + + + ns1.test.ee + + + + + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 2308' do + post '/epp/command/update', frame: request_xml + expect(response_code).to eq('2308'), "Expected EPP code of 2308, got #{response_code} (#{response_description})" + end + + it 'returns epp description' do + post '/epp/command/update', frame: request_xml + + description = 'Data management policy violation;' \ + " Nameserver count must be between #{Setting.ns_min_count}-#{Setting.ns_max_count}" \ + ' for active domains [nameservers]' + expect(response_description).to eq(description) + end + end + + context 'when nameserver count satisfies required minimum' do + let!(:domain) { create(:domain, name: 'test.com') } + let(:request_xml) { <<-XML + + + + + + test.com + + + + ns1.test.ee + + + ns2.test.ee + + + + + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 1000' do + post '/epp/command/update', frame: request_xml + expect(response_code).to eq('1000'), "Expected EPP code of 1000, got #{response_code} (#{response_description})" + end + + it 'removes inactive status' do + post '/epp/command/update', frame: request_xml + + domain = Domain.find_by(name: 'test.com') + expect(domain.statuses).to_not include(DomainStatus::INACTIVE) + end + end + end + + describe 'nameserver remove' do + before :example do + domain.nameservers << create(:nameserver, hostname: 'ns1.test.ee') + domain.nameservers << create(:nameserver, hostname: 'ns2.test.ee') + end + + context 'when nameserver count is less than minimum' do + let(:request_xml) { <<-XML + + + + + + test.com + + + + ns1.test.ee + + + + + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 2308' do + post '/epp/command/update', frame: request_xml + expect(response_code).to eq('2308'), "Expected EPP code of 2308, got #{response_code} (#{response_description})" + end + + it 'returns epp description' do + post '/epp/command/update', frame: request_xml + + description = 'Data management policy violation;' \ + " Nameserver count must be between #{Setting.ns_min_count}-#{Setting.ns_max_count}" \ + ' for active domains [nameservers]' + expect(response_description).to eq(description) + end + end + + context 'when all nameservers are removed' do + let(:request_xml) { <<-XML + + + + + + test.com + + + + ns1.test.ee + + + ns2.test.ee + + + + + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 1000' do + post '/epp/command/update', frame: request_xml + expect(response_code).to eq('2308'), "Expected EPP code of 1000, got #{response_code} (#{response_description})" + end + end + end +end diff --git a/spec/support/settings.rb b/spec/support/settings.rb index 7a5aebf3b..f5d0f934d 100644 --- a/spec/support/settings.rb +++ b/spec/support/settings.rb @@ -10,6 +10,8 @@ RSpec.configure do |config| Setting.dnskeys_min_count = 0 Setting.dnskeys_max_count = 9 + + Setting.nameserver_required = false Setting.ns_min_count = 2 Setting.ns_max_count = 11