diff --git a/app/controllers/epp/base_controller.rb b/app/controllers/epp/base_controller.rb index 9fa2d4e407..6a0e805d7d 100644 --- a/app/controllers/epp/base_controller.rb +++ b/app/controllers/epp/base_controller.rb @@ -1,7 +1,10 @@ module Epp - class BaseController < ApplicationController - layout false + class BaseController < ActionController::Base + class AuthorizationError < StandardError; end + + check_authorization skip_before_action :verify_authenticity_token + layout false before_action :ensure_session_id_passed before_action :generate_svtrid @@ -10,13 +13,50 @@ class BaseController < ApplicationController before_action :validate_request before_action :update_epp_session, if: 'signed_in?' - around_action :catch_epp_errors + around_action :wrap_exceptions helper_method :current_user helper_method :resource + rescue_from StandardError, with: :respond_with_command_failed_error + rescue_from AuthorizationError, with: :respond_with_authorization_error + rescue_from ActiveRecord::RecordNotFound, with: :respond_with_object_does_not_exist_error + + protected + + def respond_with_command_failed_error(exception) + epp_errors << { + code: '2400', + msg: 'Command failed', + } + handle_errors + log_exception(exception) + end + + def respond_with_object_does_not_exist_error + epp_errors << { + code: '2303', + msg: 'Object does not exist', + } + handle_errors + end + + def respond_with_authorization_error + epp_errors << { + code: '2201', + msg: 'Authorization error', + } + handle_errors + end + private + def wrap_exceptions + yield + rescue CanCan::AccessDenied + raise AuthorizationError + end + def validate_against_schema return if ['hello', 'error', 'keyrelay'].include?(params[:action]) schema.validate(params[:nokogiri_frame]).each do |error| @@ -28,47 +68,6 @@ def validate_against_schema handle_errors and return if epp_errors.any? end - def catch_epp_errors - err = catch(:epp_error) do - yield - nil - end - return unless err - @errors = [err] - handle_errors - end - - rescue_from StandardError do |e| - @errors ||= [] - - if e.class == CanCan::AccessDenied - if @errors.blank? - @errors = [{ - msg: t('errors.messages.epp_authorization_error'), - code: '2201' - }] - end - else - if @errors.blank? - @errors = [{ - msg: 'Internal error.', - code: '2400' - }] - end - - if Rails.env.test? || Rails.env.development? - puts e.backtrace.reverse.join("\n") - puts "\n BACKTRACE REVERSED!\n" - puts "\n FROM-EPP-RESCUE: #{e.message}\n\n\n" - else - logger.error "FROM-EPP-RESCUE: #{e.message}" - logger.error e.backtrace.join("\n") - end - end - - render_epp_response '/epp/error' - end - def schema EPP_ALL_SCHEMA end @@ -114,25 +113,13 @@ def handle_errors(obj = nil) end end - # for debugging - if @errors.blank? - @errors << { - code: '1', - msg: 'handle_errors was executed when there were actually no errors' - } - end - @errors.uniq! - logger.error "\nFOLLOWING ERRORS OCCURRED ON EPP QUERY:" - logger.error @errors.inspect - logger.error "\n" - render_epp_response '/epp/error' end def render_epp_response(*args) - @response = render_to_string(*args) + @response = render_to_string(*args, formats: 'xml') render xml: @response write_to_epp_log end @@ -406,5 +393,9 @@ def counter_update(registrar_code, ip) logger.error "IPTABLES COUNTER UPDATE: cannot write #{ip} to #{counter_proc}: #{e}" end end + + def log_exception(exception) + notify_airbrake(exception) + end end end diff --git a/app/controllers/epp/contacts_controller.rb b/app/controllers/epp/contacts_controller.rb index ff5dc982fa..32b2050ca3 100644 --- a/app/controllers/epp/contacts_controller.rb +++ b/app/controllers/epp/contacts_controller.rb @@ -84,18 +84,7 @@ def find_password def find_contact code = params[:parsed_frame].css('id').text.strip.upcase - - @contact = Epp::Contact.find_by_epp_code(code) - - if @contact.blank? - epp_errors << { - code: '2303', - msg: t('errors.messages.epp_obj_does_not_exist'), - value: { obj: 'id', val: code } - } - fail CanCan::AccessDenied - end - @contact + @contact = Epp::Contact.find_by!(code: code) end # diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index 64d4e972e0..2f31f7e5e7 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -4,10 +4,14 @@ class DomainsController < BaseController before_action :find_password, only: %i[info update transfer delete] def info - authorize! :info, @domain, @password + authorize! :info, @domain @hosts = params[:parsed_frame].css('name').first['hosts'] || 'all' + sponsoring_registrar = (@domain.registrar == current_user.registrar) + correct_transfer_code_provided = (@domain.transfer_code == @password) + @reveal_full_details = (sponsoring_registrar || correct_transfer_code_provided) + case @hosts when 'del' @nameservers = @domain.delegated_nameservers.sort @@ -28,26 +32,38 @@ def create domain_name = DNS::DomainName.new(SimpleIDN.to_unicode(request_domain_name)) if domain_name.at_auction? - throw :epp_error, - code: '2306', - msg: 'Parameter value policy error: domain is at auction' + epp_errors << { + code: '2306', + msg: 'Parameter value policy error: domain is at auction', + } + handle_errors + return elsif domain_name.awaiting_payment? - throw :epp_error, - code: '2003', - msg: 'Required parameter missing; reserved>pw element required for reserved domains' + epp_errors << { + code: '2003', + msg: 'Required parameter missing; reserved>pw element required for reserved domains', + } + handle_errors + return elsif domain_name.pending_registration? registration_code = params[:parsed_frame].css('reserved > pw').text if registration_code.empty? - throw :epp_error, - code: '2003', - msg: 'Required parameter missing; reserved>pw element is required' + epp_errors << { + code: '2003', + msg: 'Required parameter missing; reserved>pw element is required', + } + handle_errors + return end unless domain_name.available_with_code?(registration_code) - throw :epp_error, - code: '2202', - msg: 'Invalid authorization information; invalid reserved>pw value' + epp_errors << { + code: '2202', + msg: 'Invalid authorization information; invalid reserved>pw value', + } + handle_errors + return end end end @@ -85,22 +101,15 @@ def create def update authorize! :update, @domain, @password - begin - if @domain.update(params[:parsed_frame], current_user) - if @domain.epp_pending_update.present? - render_epp_response '/epp/domains/success_pending' - else - render_epp_response '/epp/domains/success' - end - else - handle_errors(@domain) - end - rescue => e - if @domain.errors.any? - handle_errors(@domain) + + if @domain.update(params[:parsed_frame], current_user) + if @domain.epp_pending_update.present? + render_epp_response '/epp/domains/success_pending' else - throw e + render_epp_response '/epp/domains/success' end + else + handle_errors(@domain) end end @@ -173,18 +182,37 @@ def renew end def transfer - authorize! :transfer, @domain, @password + authorize! :transfer, @domain action = params[:parsed_frame].css('transfer').first[:op] if @domain.non_transferable? - throw :epp_error, { + epp_errors << { code: '2304', - msg: I18n.t(:object_status_prohibits_operation) + msg: I18n.t(:object_status_prohibits_operation), + } + handle_errors + return + end + + provided_transfer_code = params[:parsed_frame].css('authInfo pw').text + wrong_transfer_code = provided_transfer_code != @domain.transfer_code + + if wrong_transfer_code + epp_errors << { + code: '2202', + msg: 'Invalid authorization information', } + handle_errors + return end @domain_transfer = @domain.transfer(params[:parsed_frame], action, current_user) + if @domain.errors[:epp_errors].any? + handle_errors(@domain) + return + end + if @domain_transfer render_epp_response '/epp/domains/transfer' else @@ -272,18 +300,11 @@ def validate_transfer def find_domain domain_name = params[:parsed_frame].css('name').text.strip.downcase - @domain = Epp::Domain.find_by_idn domain_name - unless @domain - epp_errors << { - code: '2303', - msg: I18n.t('errors.messages.epp_domain_not_found'), - value: { obj: 'name', val: domain_name } - } - fail CanCan::AccessDenied - end + domain = Epp::Domain.find_by_idn(domain_name) + raise ActiveRecord::RecordNotFound unless domain - @domain + @domain = domain end def find_password diff --git a/app/models/ability.rb b/app/models/ability.rb index 50e87c98eb..706d851801 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -48,13 +48,12 @@ def epp # Registrar/api_user dynamic role # can(:create, :epp_request) # Epp::Domain - can(:info, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || pw.blank? ? true : d.transfer_code == pw } + can(:info, Epp::Domain) can(:check, Epp::Domain) can(:create, Epp::Domain) can(:renew, Epp::Domain) { |d| d.registrar_id == @user.registrar_id } can(:update, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw } - can(:transfer, Epp::Domain) { |d, pw| d.transfer_code == pw } - can(:view_password, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw } + can(:transfer, Epp::Domain) can(:delete, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw } # Epp::Contact diff --git a/app/models/epp/contact.rb b/app/models/epp/contact.rb index a33e55a0ee..8ea01b67d2 100644 --- a/app/models/epp/contact.rb +++ b/app/models/epp/contact.rb @@ -154,10 +154,17 @@ def update_attributes(frame, current_user) type: ident_frame.attr('type'), country_code: ident_frame.attr('cc')) - report_valid_ident_error if submitted_ident != identifier + if submitted_ident != identifier + add_epp_error('2308', nil, nil, I18n.t('epp.contacts.errors.valid_ident')) + return + end else ident_update_attempt = ident_frame.text.present? && (ident_frame.text != ident) - report_ident_update_error if ident_update_attempt + + if ident_update_attempt + add_epp_error('2308', nil, nil, I18n.t('epp.contacts.errors.ident_update')) + return + end identifier = Ident.new(code: ident, type: ident_frame.attr('type'), @@ -243,14 +250,4 @@ def add_legal_file_to_new frame frame.css("legalDocument").first.content = doc.path if doc&.persisted? self.legal_document_id = doc.id end - - private - - def report_valid_ident_error - throw :epp_error, { code: '2308', msg: I18n.t('epp.contacts.errors.valid_ident') } - end - - def report_ident_update_error - throw :epp_error, { code: '2308', msg: I18n.t('epp.contacts.errors.ident_update') } - end end diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index f5db59ebb1..19933a5ebb 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -451,10 +451,8 @@ def update(frame, current_user, verify = true) return super if frame.blank? if discarded? - throw :epp_error, { - code: '2304', - msg: 'Object status prohibits operation', - } + add_epp_error('2304', nil, nil, 'Object status prohibits operation') + return end at = {}.with_indifferent_access @@ -531,10 +529,8 @@ def attach_legal_document(legal_document_data) def epp_destroy(frame, user_id) if discarded? - throw :epp_error, { - code: '2304', - msg: 'Object status prohibits operation', - } + add_epp_error('2304', nil, nil, 'Object status prohibits operation') + return end if doc = attach_legal_document(Epp::Domain.parse_legal_document_from_frame(frame)) @@ -554,10 +550,10 @@ def epp_destroy(frame, user_id) end def set_pending_delete! - throw :epp_error, { - code: '2304', - msg: I18n.t(:object_status_prohibits_operation) - } unless pending_deletable? + unless pending_deletable? + add_epp_error('2304', nil, nil, I18n.t(:object_status_prohibits_operation)) + return + end self.delete_date = Time.zone.today + Setting.redemption_grace_period.days + 1.day set_pending_delete @@ -601,10 +597,8 @@ def renew(cur_exp_date, period, unit = 'y') def transfer(frame, action, current_user) if discarded? - throw :epp_error, { - code: '2106', - msg: 'Object is not eligible for transfer', - } + add_epp_error('2106', nil, nil, 'Object is not eligible for transfer') + return end @is_transfer = true @@ -624,10 +618,8 @@ def transfer(frame, action, current_user) def query_transfer(frame, current_user) if current_user.registrar == registrar - throw :epp_error, { - code: '2002', - msg: I18n.t(:domain_already_belongs_to_the_querying_registrar) - } + add_epp_error('2002', nil, nil, I18n.t(:domain_already_belongs_to_the_querying_registrar)) + return end transaction do @@ -661,11 +653,10 @@ def query_transfer(frame, current_user) def approve_transfer(frame, current_user) pt = pending_transfer + if current_user.registrar != pt.old_registrar - throw :epp_error, { - msg: I18n.t('transfer_can_be_approved_only_by_current_registrar'), - code: '2304' - } + add_epp_error('2304', nil, nil, I18n.t('transfer_can_be_approved_only_by_current_registrar')) + return end transaction do @@ -687,11 +678,10 @@ def approve_transfer(frame, current_user) def reject_transfer(frame, current_user) pt = pending_transfer + if current_user.registrar != pt.old_registrar - throw :epp_error, { - msg: I18n.t('transfer_can_be_rejected_only_by_current_registrar'), - code: '2304' - } + add_epp_error('2304', nil, nil, I18n.t('transfer_can_be_rejected_only_by_current_registrar')) + return end transaction do diff --git a/app/models/epp/response/result/code.rb b/app/models/epp/response/result/code.rb index d880df6c62..403f67435f 100644 --- a/app/models/epp/response/result/code.rb +++ b/app/models/epp/response/result/code.rb @@ -26,6 +26,7 @@ class Code object_association_prohibits_operation: 2305, parameter_value_policy_error: 2306, data_management_policy_violation: 2308, + command_failed: 2400, authentication_error_server_closing_connection: 2501, }.freeze private_constant :KEY_TO_VALUE @@ -52,6 +53,7 @@ class Code 2305 => 'Object association prohibits operation', 2306 => 'Parameter value policy error', 2308 => 'Data management policy violation', + 2400 => 'Command failed', 2501 => 'Authentication error; server closing connection', }.freeze private_constant :DEFAULT_DESCRIPTIONS diff --git a/app/views/epp/domains/info.xml.builder b/app/views/epp/domains/info.xml.builder index 937da30a42..ce5d609414 100644 --- a/app/views/epp/domains/info.xml.builder +++ b/app/views/epp/domains/info.xml.builder @@ -53,7 +53,7 @@ xml.epp_head do xml.tag!('domain:exDate', @domain.valid_to.iso8601) - if can? :view_password, @domain, @password + if @reveal_full_details xml.tag!('domain:authInfo') do xml.tag!('domain:pw', @domain.transfer_code) end diff --git a/app/views/epp/latin_error.xml.builder b/app/views/epp/latin_error.xml.builder deleted file mode 100644 index 6ff19efbf5..0000000000 --- a/app/views/epp/latin_error.xml.builder +++ /dev/null @@ -1,8 +0,0 @@ -xml.epp_head do - xml.response do - xml.result('code' => '2306') do - xml.msg('Parameter value policy error. Allowed only Latin characters.', 'lang' => 'en') - end - render('epp/shared/trID', builder: xml) - end -end diff --git a/config/locales/en.yml b/config/locales/en.yml index 8beb4bed23..9d89726b17 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -202,7 +202,6 @@ en: epp_domain_zone_with_same_origin: Zone with the same origin exists epp_domain_at_auction: Domain is at auction epp_domain_awaiting_payment: Awaiting payment - epp_obj_does_not_exist: 'Object does not exist' epp_authorization_error: 'Authorization error' epp_id_taken: 'Contact id already exists' epp_domain_not_found: 'Domain not found' diff --git a/test/integration/epp/base_test.rb b/test/integration/epp/base_test.rb new file mode 100644 index 0000000000..eb02c42e8f --- /dev/null +++ b/test/integration/epp/base_test.rb @@ -0,0 +1,90 @@ +require 'test_helper' + +class DummyEppController < Epp::BaseController + def internal_error + raise StandardError + end +end + +class EppBaseTest < EppTestCase + def test_internal_error + Rails.application.routes.draw do + post 'epp/command/internal_error', to: 'dummy_epp#internal_error', + constraints: EppConstraint.new(:poll) + end + + any_valid_epp_request_xml = <<-XML + + + + + XML + + begin + assert_difference 'ApiLog::EppLog.count' do + post '/epp/command/internal_error', { frame: any_valid_epp_request_xml }, + 'HTTP_COOKIE' => 'session=api_bestnames' + end + assert_epp_response :command_failed + rescue + raise + ensure + Rails.application.reload_routes! + end + end + + def test_invalid_request + invalid_xml = <<-XML + + + + XML + post '/epp/command/internal_error', { frame: invalid_xml }, + 'HTTP_COOKIE' => 'session=api_bestnames' + + assert_epp_response :syntax_error + end + + def test_anonymous_user + xml_of_epp_command_that_requires_authentication = <<-XML + + + + + + #{domains(:shop).name} + + + + + XML + post '/epp/command/info', { frame: xml_of_epp_command_that_requires_authentication }, + 'HTTP_COOKIE' => 'session=non-existent' + + assert_epp_response :authorization_error + end + + def test_non_authorized_user + session = epp_sessions(:api_bestnames) + user = session.user + user.update!(roles: [ApiUser::BILLING]) + assert user.cannot?(:info, Domain) + + xml_of_epp_command_that_requires_authorization = <<-XML + + + + + + #{domains(:shop).name} + + + + + XML + post '/epp/command/info', { frame: xml_of_epp_command_that_requires_authorization }, + 'HTTP_COOKIE' => "session=#{session.session_id}" + + assert_epp_response :authorization_error + end +end diff --git a/test/integration/epp/contact/base_test.rb b/test/integration/epp/contact/base_test.rb new file mode 100644 index 0000000000..c332e7b361 --- /dev/null +++ b/test/integration/epp/contact/base_test.rb @@ -0,0 +1,21 @@ +require 'test_helper' + +class EppContactBaseTest < EppTestCase + def test_non_existent_contact + request_xml = <<-XML + + + + + + non-existent + + + + + XML + post '/epp/command/info', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + + assert_epp_response :object_does_not_exist + end +end diff --git a/test/integration/epp/contact/info/base_test.rb b/test/integration/epp/contact/info/base_test.rb index c871eb636a..d535d14d5e 100644 --- a/test/integration/epp/contact/info/base_test.rb +++ b/test/integration/epp/contact/info/base_test.rb @@ -43,27 +43,6 @@ def test_returns_valid_response contact: xml_schema).text end - def test_contact_not_found - assert_nil Contact.find_by(code: 'non-existing') - - request_xml = <<-XML - - - - - - non-existing - - - - - XML - - post '/epp/command/info', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' - - assert_epp_response :object_does_not_exist - end - private def xml_schema diff --git a/test/integration/epp/contact/update/base_test.rb b/test/integration/epp/contact/update/base_test.rb index a8bb1d7a20..2362a44697 100644 --- a/test/integration/epp/contact/update/base_test.rb +++ b/test/integration/epp/contact/update/base_test.rb @@ -133,32 +133,6 @@ def test_skips_notifying_a_contact_when_a_contact_is_not_a_registrant assert_no_emails end - def test_non_existing_contact - assert_nil Contact.find_by(code: 'non-existing') - - request_xml = <<-XML - - - - - - non-existing - - - any - - - - - - - XML - - post '/epp/command/update', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' - - assert_epp_response :object_does_not_exist - end - private def make_contact_free_of_domains_where_it_acts_as_a_registrant(contact) diff --git a/test/integration/epp/domain/base_test.rb b/test/integration/epp/domain/base_test.rb new file mode 100644 index 0000000000..b12fcf8da2 --- /dev/null +++ b/test/integration/epp/domain/base_test.rb @@ -0,0 +1,21 @@ +require 'test_helper' + +class EppDomainBaseTest < EppTestCase + def test_non_existent_domain + request_xml = <<-XML + + + + + + non-existent.test + + + + + XML + post '/epp/command/info', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + + assert_epp_response :object_does_not_exist + end +end diff --git a/test/integration/epp/domain/delete/base_test.rb b/test/integration/epp/domain/delete/base_test.rb index 9cf26f206e..a194e8ce2e 100644 --- a/test/integration/epp/domain/delete/base_test.rb +++ b/test/integration/epp/domain/delete/base_test.rb @@ -207,30 +207,4 @@ def test_domain_cannot_be_deleted_when_explicitly_prohibited_by_registrar assert_epp_response :object_status_prohibits_operation end - - def test_domain_not_found - assert_nil Domain.find_by(name: 'non-existing.test') - - request_xml = <<-XML - - - - - - non-existing.test - - - - - dGVzdCBmYWlsCg== - - - - - XML - - post '/epp/command/delete', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' - - assert_epp_response :object_does_not_exist - end end \ No newline at end of file diff --git a/test/integration/epp/domain/info/base_test.rb b/test/integration/epp/domain/info/base_test.rb index 0aebc4de51..fd90177ca3 100644 --- a/test/integration/epp/domain/info/base_test.rb +++ b/test/integration/epp/domain/info/base_test.rb @@ -105,25 +105,4 @@ def test_conceals_transfer_code_when_domain_is_not_owned_by_current_user assert_nil response_xml.at_xpath('//domain:authInfo/domain:pw', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd') end - - def test_returns_not_found_error_when_domain_is_not_registered - assert DNS::DomainName.new('not-registered.test').not_registered? - - request_xml = <<-XML - - - - - - not-registered.test - - - - - XML - - post '/epp/command/info', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' - - assert_epp_response :object_does_not_exist - end end \ No newline at end of file diff --git a/test/integration/epp/domain/transfer/base_test.rb b/test/integration/epp/domain/transfer/base_test.rb deleted file mode 100644 index 5c15ae8816..0000000000 --- a/test/integration/epp/domain/transfer/base_test.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'test_helper' - -class EppDomainTransferBaseTest < EppTestCase - def test_non_existent_domain - request_xml = <<-XML - - - - - - non-existent.test - - any - - - - - - XML - - post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } - - assert_epp_response :object_does_not_exist - end -end diff --git a/test/integration/epp/domain/transfer/query_test.rb b/test/integration/epp/domain/transfer/query_test.rb index e3bf7bdae4..bd12937715 100644 --- a/test/integration/epp/domain/transfer/query_test.rb +++ b/test/integration/epp/domain/transfer/query_test.rb @@ -30,8 +30,7 @@ def test_wrong_transfer_code post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } - # https://github.com/internetee/registry/issues/686 - assert_epp_response :authorization_error + assert_epp_response :invalid_authorization_information end def test_no_domain_transfer diff --git a/test/integration/epp/domain/transfer/request_test.rb b/test/integration/epp/domain/transfer/request_test.rb index 877076be7f..6a1b5a9f1f 100644 --- a/test/integration/epp/domain/transfer/request_test.rb +++ b/test/integration/epp/domain/transfer/request_test.rb @@ -115,10 +115,9 @@ def test_wrong_transfer_code post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } @domain.reload - refute_equal @new_registrar, @domain.registrar - # https://github.com/internetee/registry/issues/686 - assert_epp_response :authorization_error + assert_epp_response :invalid_authorization_information + refute_equal @new_registrar, @domain.registrar end private diff --git a/test/models/epp/response/result/code_test.rb b/test/models/epp/response/result/code_test.rb index 2ee0f013fa..556ff17ef0 100644 --- a/test/models/epp/response/result/code_test.rb +++ b/test/models/epp/response/result/code_test.rb @@ -47,6 +47,7 @@ def test_returns_code_values object_association_prohibits_operation: 2305, parameter_value_policy_error: 2306, data_management_policy_violation: 2308, + command_failed: 2400, authentication_error_server_closing_connection: 2501, } assert_equal codes, Epp::Response::Result::Code.codes @@ -75,6 +76,7 @@ def test_returns_default_descriptions 2305 => 'Object association prohibits operation', 2306 => 'Parameter value policy error', 2308 => 'Data management policy violation', + 2400 => 'Command failed', 2501 => 'Authentication error; server closing connection', } assert_equal descriptions, Epp::Response::Result::Code.default_descriptions