From 39f9ff13d12b63848c801c06ba588b66affe3daa Mon Sep 17 00:00:00 2001 From: Artur Beljajev Date: Tue, 24 Jan 2017 13:49:45 +0200 Subject: [PATCH 1/4] Remove unused class #355 --- app/jobs/domain_set_delete_candidate_job.rb | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 app/jobs/domain_set_delete_candidate_job.rb diff --git a/app/jobs/domain_set_delete_candidate_job.rb b/app/jobs/domain_set_delete_candidate_job.rb deleted file mode 100644 index f1e489694..000000000 --- a/app/jobs/domain_set_delete_candidate_job.rb +++ /dev/null @@ -1,10 +0,0 @@ -class DomainSetDeleteCandidateJob < Que::Job - - def run(domain_id) - domain = Domain.find(domain_id) - domain.statuses << DomainStatus::DELETE_CANDIDATE - ::PaperTrail.whodunnit = "job - #{self.class.name}" - domain.save(validate: false) - DomainDeleteJob.enqueue(domain.id, run_at: rand(((24*60) - (DateTime.now.hour * 60 + DateTime.now.minute))).minutes.from_now) - end -end From edf1e3326086ca482bd61f437f4ff99ae976c042 Mon Sep 17 00:00:00 2001 From: Artur Beljajev Date: Tue, 24 Jan 2017 19:16:15 +0200 Subject: [PATCH 2/4] Disallow EPP domain:update/transfer/delete if a domain has "deleteCandidate" status #355 --- CHANGELOG.md | 3 ++ app/models/concerns/domain/deletable.rb | 11 +++++ app/models/domain.rb | 2 +- app/models/epp/domain.rb | 18 +++++++ spec/factories/domain.rb | 4 ++ spec/models/concerns/domain/deletable_spec.rb | 19 ++++++++ spec/models/domain_spec.rb | 1 - .../epp/domain/delete/discarded_spec.rb | 48 +++++++++++++++++++ .../epp/domain/transfer/discarded_spec.rb | 46 ++++++++++++++++++ .../epp/domain/update/discarded_spec.rb | 43 +++++++++++++++++ 10 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 app/models/concerns/domain/deletable.rb create mode 100644 spec/models/concerns/domain/deletable_spec.rb create mode 100644 spec/requests/epp/domain/delete/discarded_spec.rb create mode 100644 spec/requests/epp/domain/transfer/discarded_spec.rb create mode 100644 spec/requests/epp/domain/update/discarded_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index a6517b4ff..157cc9501 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +24.01.2017 +* Disallow EPP domain:update/transfer/delete if a domain has "deleteCandidate" status + 22.12.2016 * Return business registry code and country for 'org' type registrants in WHOIS and Rest-WHOIS diff --git a/app/models/concerns/domain/deletable.rb b/app/models/concerns/domain/deletable.rb new file mode 100644 index 000000000..f724162e5 --- /dev/null +++ b/app/models/concerns/domain/deletable.rb @@ -0,0 +1,11 @@ +module Concerns::Domain::Deletable + extend ActiveSupport::Concern + + included do + alias_attribute :delete_time, :delete_at + end + + def discarded? + statuses.include?(DomainStatus::DELETE_CANDIDATE) + end +end diff --git a/app/models/domain.rb b/app/models/domain.rb index bca5942ac..3e71dd1e9 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -5,6 +5,7 @@ class Domain < ActiveRecord::Base include Concerns::Domain::Expirable include Concerns::Domain::Activatable include Concerns::Domain::ForceDelete + include Concerns::Domain::Deletable has_paper_trail class_name: "DomainVersion", meta: { children: :children_log } @@ -14,7 +15,6 @@ class Domain < ActiveRecord::Base alias_attribute :on_hold_time, :outzone_at alias_attribute :outzone_time, :outzone_at - alias_attribute :delete_time, :delete_at # TODO: whois requests ip whitelist for full info for own domains and partial info for other domains # TODO: most inputs should be trimmed before validatation, probably some global logic? diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 6a2edf5ed..a2a5dd1dc 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -472,6 +472,9 @@ class Epp::Domain < Domain # rubocop: disable Metrics/CyclomaticComplexity def update(frame, current_user, verify = true) return super if frame.blank? + + check_discarded + at = {}.with_indifferent_access at.deep_merge!(attrs_from(frame.css('chg'), current_user, 'chg')) at.deep_merge!(attrs_from(frame.css('rem'), current_user, 'rem')) @@ -563,6 +566,8 @@ class Epp::Domain < Domain def epp_destroy(frame, user_id) return false unless valid? + check_discarded + if doc = attach_legal_document(Epp::Domain.parse_legal_document_from_frame(frame)) frame.css("legalDocument").first.content = doc.path if doc && doc.persisted? end @@ -629,6 +634,8 @@ class Epp::Domain < Domain # rubocop: disable Metrics/CyclomaticComplexity def transfer(frame, action, current_user) + check_discarded + @is_transfer = true case action @@ -925,5 +932,16 @@ class Epp::Domain < Domain res end end + + private + + def check_discarded + if discarded? + throw :epp_error, { + code: '2105', + msg: I18n.t(:object_is_not_eligible_for_renewal), + } + end + end end # rubocop: enable Metrics/ClassLength diff --git a/spec/factories/domain.rb b/spec/factories/domain.rb index edbd2274c..4c1b4b1cc 100644 --- a/spec/factories/domain.rb +++ b/spec/factories/domain.rb @@ -15,5 +15,9 @@ FactoryGirl.define do force_delete_time nil statuses [] end + + factory :domain_discarded do + statuses [DomainStatus::DELETE_CANDIDATE] + end end end diff --git a/spec/models/concerns/domain/deletable_spec.rb b/spec/models/concerns/domain/deletable_spec.rb new file mode 100644 index 000000000..826299b69 --- /dev/null +++ b/spec/models/concerns/domain/deletable_spec.rb @@ -0,0 +1,19 @@ +require 'rails_helper' + +RSpec.describe Domain, db: false do + it { is_expected.to alias_attribute(:delete_time, :delete_at) } + + describe '#discarded?' do + context 'when :deleteCandidate status is present' do + let(:domain) { described_class.new(statuses: [DomainStatus::DELETE_CANDIDATE]) } + + specify { expect(domain).to be_discarded } + end + + context 'when :deleteCandidate status is absent' do + let(:domain) { described_class.new(statuses: []) } + + specify { expect(domain).to_not be_discarded } + end + end +end diff --git a/spec/models/domain_spec.rb b/spec/models/domain_spec.rb index 6e224080f..65c96dbe8 100644 --- a/spec/models/domain_spec.rb +++ b/spec/models/domain_spec.rb @@ -607,7 +607,6 @@ end RSpec.describe Domain, db: false do it { is_expected.to alias_attribute(:on_hold_time, :outzone_at) } - it { is_expected.to alias_attribute(:delete_time, :delete_at) } it { is_expected.to alias_attribute(:outzone_time, :outzone_at) } describe 'nameserver validation', db: true do diff --git a/spec/requests/epp/domain/delete/discarded_spec.rb b/spec/requests/epp/domain/delete/discarded_spec.rb new file mode 100644 index 000000000..f136e0696 --- /dev/null +++ b/spec/requests/epp/domain/delete/discarded_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe 'EPP domain:delete' do + let(:request_xml) { <<-XML + + + + + + test.com + + + + + dGVzdCBmYWlsCg== + + + + + XML + } + + 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 + end + + context 'when domain is not discarded' do + let!(:domain) { create(:domain, name: 'test.com') } + + it 'returns epp code of 1001' do + post '/epp/command/delete', frame: request_xml + expect(response_code).to eq('1001'), "Expected EPP code of 1001, got #{response_code} (#{response_description})" + end + end + + context 'when domain is discarded' do + let!(:domain) { create(:domain_discarded, name: 'test.com') } + + it 'returns epp code of 2105' do + post '/epp/command/delete', frame: request_xml + expect(response_code).to eq('2105'), "Expected EPP code of 2105, got #{response_code} (#{response_description})" + end + end +end diff --git a/spec/requests/epp/domain/transfer/discarded_spec.rb b/spec/requests/epp/domain/transfer/discarded_spec.rb new file mode 100644 index 000000000..045e3cd2f --- /dev/null +++ b/spec/requests/epp/domain/transfer/discarded_spec.rb @@ -0,0 +1,46 @@ +require 'rails_helper' + +RSpec.describe 'EPP domain:transfer' do + let(:request_xml) { <<-XML + + + + + + test.com + + 98oiewslkfkd + + + + + + XML + } + + 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 + end + + context 'when domain is not discarded' do + let!(:domain) { create(:domain, name: 'test.com') } + + it 'returns epp code of 1000' do + post '/epp/command/transfer', frame: request_xml + expect(response_code).to eq('1000'), "Expected EPP code of 1000, got #{response_code} (#{response_description})" + end + end + + context 'when domain is discarded' do + let!(:domain) { create(:domain_discarded, name: 'test.com') } + + it 'returns epp code of 2105' do + post '/epp/command/transfer', frame: request_xml + expect(response_code).to eq('2105'), "Expected EPP code of 2105, got #{response_code} (#{response_description})" + end + end +end diff --git a/spec/requests/epp/domain/update/discarded_spec.rb b/spec/requests/epp/domain/update/discarded_spec.rb new file mode 100644 index 000000000..c1061a95f --- /dev/null +++ b/spec/requests/epp/domain/update/discarded_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' + +RSpec.describe 'EPP domain:update' do + let(:request_xml) { <<-XML + + + + + + test.com + + + + + XML + } + + 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 + end + + context 'when domain is not discarded' do + let!(:domain) { create(:domain, name: 'test.com') } + + 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 + end + + context 'when domain is discarded' do + let!(:domain) { create(:domain_discarded, name: 'test.com') } + + it 'returns epp code of 2105' do + post '/epp/command/update', frame: request_xml + expect(response_code).to eq('2105'), "Expected EPP code of 2105, got #{response_code} (#{response_description})" + end + end +end From e31c68d43fe4dd11de1d3cac1e2ff506d5cb18ae Mon Sep 17 00:00:00 2001 From: Artur Beljajev Date: Wed, 25 Jan 2017 05:11:31 +0200 Subject: [PATCH 3/4] Add EPP response code rspec matcher #355 --- spec/rails_helper.rb | 8 +++++ .../epp/domain/delete/discarded_spec.rb | 8 ++--- .../epp/domain/transfer/discarded_spec.rb | 8 ++--- .../epp/domain/update/discarded_spec.rb | 8 ++--- spec/support/matchers/epp/code.rb | 35 +++++++++++++++++++ spec/support/requests/epp_helpers.rb | 7 ++++ 6 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 spec/support/matchers/epp/code.rb create mode 100644 spec/support/requests/epp_helpers.rb diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 402db389d..bfe87211b 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -6,6 +6,7 @@ require 'capybara/poltergeist' require 'paper_trail/frameworks/rspec' require 'money-rails/test_helpers' require 'support/requests/session_helpers' +require 'support/requests/epp_helpers' require 'support/features/session_helpers' if ENV['ROBOT'] @@ -15,6 +16,7 @@ end require 'support/matchers/alias_attribute' require 'support/matchers/active_job' +require 'support/matchers/epp/code' require 'support/capybara' require 'support/factory_girl' require 'support/database_cleaner' @@ -30,6 +32,8 @@ RSpec.configure do |config| config.include Features::SessionHelpers, type: :feature config.include AbstractController::Translation, type: :feature + config.include Requests::EPPHelpers, epp: true + config.define_derived_metadata(file_path: %r[/spec/features/]) do |metadata| metadata[:db] = true if metadata[:db].nil? end @@ -46,6 +50,10 @@ RSpec.configure do |config| metadata[:db] = true if metadata[:db].nil? end + config.define_derived_metadata(file_path: %r[/spec/requests/epp/]) do |metadata| + metadata[:epp] = true if metadata[:epp].nil? + end + config.define_derived_metadata(file_path: %r[/spec/api/]) do |metadata| metadata[:type] = :request end diff --git a/spec/requests/epp/domain/delete/discarded_spec.rb b/spec/requests/epp/domain/delete/discarded_spec.rb index f136e0696..99ec59267 100644 --- a/spec/requests/epp/domain/delete/discarded_spec.rb +++ b/spec/requests/epp/domain/delete/discarded_spec.rb @@ -20,10 +20,6 @@ RSpec.describe 'EPP domain:delete' do XML } - 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 end @@ -33,7 +29,7 @@ RSpec.describe 'EPP domain:delete' do it 'returns epp code of 1001' do post '/epp/command/delete', frame: request_xml - expect(response_code).to eq('1001'), "Expected EPP code of 1001, got #{response_code} (#{response_description})" + expect(response).to have_code_of(1001) end end @@ -42,7 +38,7 @@ RSpec.describe 'EPP domain:delete' do it 'returns epp code of 2105' do post '/epp/command/delete', frame: request_xml - expect(response_code).to eq('2105'), "Expected EPP code of 2105, got #{response_code} (#{response_description})" + expect(response).to have_code_of(2105) end end end diff --git a/spec/requests/epp/domain/transfer/discarded_spec.rb b/spec/requests/epp/domain/transfer/discarded_spec.rb index 045e3cd2f..51f65c641 100644 --- a/spec/requests/epp/domain/transfer/discarded_spec.rb +++ b/spec/requests/epp/domain/transfer/discarded_spec.rb @@ -18,10 +18,6 @@ RSpec.describe 'EPP domain:transfer' do XML } - 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 end @@ -31,7 +27,7 @@ RSpec.describe 'EPP domain:transfer' do it 'returns epp code of 1000' do post '/epp/command/transfer', frame: request_xml - expect(response_code).to eq('1000'), "Expected EPP code of 1000, got #{response_code} (#{response_description})" + expect(response).to have_code_of(1000) end end @@ -40,7 +36,7 @@ RSpec.describe 'EPP domain:transfer' do it 'returns epp code of 2105' do post '/epp/command/transfer', frame: request_xml - expect(response_code).to eq('2105'), "Expected EPP code of 2105, got #{response_code} (#{response_description})" + expect(response).to have_code_of(2105) end end end diff --git a/spec/requests/epp/domain/update/discarded_spec.rb b/spec/requests/epp/domain/update/discarded_spec.rb index c1061a95f..14ff1c743 100644 --- a/spec/requests/epp/domain/update/discarded_spec.rb +++ b/spec/requests/epp/domain/update/discarded_spec.rb @@ -15,10 +15,6 @@ RSpec.describe 'EPP domain:update' do XML } - 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 end @@ -28,7 +24,7 @@ RSpec.describe 'EPP domain:update' do 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})" + expect(response).to have_code_of(1000) end end @@ -37,7 +33,7 @@ RSpec.describe 'EPP domain:update' do it 'returns epp code of 2105' do post '/epp/command/update', frame: request_xml - expect(response_code).to eq('2105'), "Expected EPP code of 2105, got #{response_code} (#{response_description})" + expect(response).to have_code_of(2105) end end end diff --git a/spec/support/matchers/epp/code.rb b/spec/support/matchers/epp/code.rb new file mode 100644 index 000000000..db79488b3 --- /dev/null +++ b/spec/support/matchers/epp/code.rb @@ -0,0 +1,35 @@ +module Matchers + module EPP + class Code + def initialize(expected) + @expected = expected + end + + def matches?(response) + @xml = response.body + actual == expected + end + + def failure_message + "Expected EPP code of #{expected}, got #{actual} (#{description})" + end + + private + + attr_reader :xml + attr_reader :expected + + def actual + xml_document.xpath('//xmlns:result').first['code'].to_i + end + + def description + xml_document.css('result msg').text + end + + def xml_document + @xml_document ||= Nokogiri::XML(xml) + end + end + end +end diff --git a/spec/support/requests/epp_helpers.rb b/spec/support/requests/epp_helpers.rb new file mode 100644 index 000000000..1372ae779 --- /dev/null +++ b/spec/support/requests/epp_helpers.rb @@ -0,0 +1,7 @@ +module Requests + module EPPHelpers + def have_code_of(*args) + Matchers::EPP::Code.new(*args) + end + end +end From 13a92c98698a826d2232e34e52837a2ff92025ed Mon Sep 17 00:00:00 2001 From: Artur Beljajev Date: Wed, 25 Jan 2017 13:06:13 +0200 Subject: [PATCH 4/4] Fix EPP schema #355 --- spec/requests/epp/domain/delete/discarded_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/epp/domain/delete/discarded_spec.rb b/spec/requests/epp/domain/delete/discarded_spec.rb index 99ec59267..91a527890 100644 --- a/spec/requests/epp/domain/delete/discarded_spec.rb +++ b/spec/requests/epp/domain/delete/discarded_spec.rb @@ -11,7 +11,7 @@ RSpec.describe 'EPP domain:delete' do - + dGVzdCBmYWlsCg==