diff --git a/Guardfile b/Guardfile index 7f9b167e1..c03e7c426 100644 --- a/Guardfile +++ b/Guardfile @@ -26,7 +26,11 @@ group :red_green_refactor, halt_on_fail: true do # Martin does not want rubocop unless Socket.gethostname == 'martin' - guard :rubocop, cli: '--display-cop-names -c .rubocop-guard.yml -f fuubar', notification: false do + guard :rubocop, + all_on_start: false, + cli: '--display-cop-names -c .rubocop-guard.yml -f fuubar', + notification: false do + watch(%r{.+\.rb$}) watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) } watch(%r{(?:.+/)?\.rubocop-guard\.yml$}) { |m| File.dirname(m[0]) } diff --git a/app/controllers/concerns/epp/common.rb b/app/controllers/concerns/epp/common.rb index d43b82190..f5cb2e33e 100644 --- a/app/controllers/concerns/epp/common.rb +++ b/app/controllers/concerns/epp/common.rb @@ -63,6 +63,19 @@ module Epp::Common @errors += obj.errors[:epp_errors] end + def epp_request_valid?(*selectors) + selectors.each do |selector| + el = parsed_frame.css(selector).first + next unless el + epp_errors << { + code: '2003', + msg: I18n.t('errors.messages.required_parameter_missing', key: el.name) + } unless el.text.present? + end + + epp_errors.empty? + end + def xml_attrs_present?(ph, attributes) attributes.each do |x| epp_errors << { diff --git a/app/helpers/epp/keyrelay_helper.rb b/app/helpers/epp/keyrelay_helper.rb index f1b12ae5c..b3debfba2 100644 --- a/app/helpers/epp/keyrelay_helper.rb +++ b/app/helpers/epp/keyrelay_helper.rb @@ -1,30 +1,53 @@ module Epp::KeyrelayHelper + # rubocop: disable Metrics/PerceivedComplexity + # rubocop: disable Metrics/CyclomaticComplexity def keyrelay - domain = Domain.find_by(name: parsed_frame.css('name').text) + handle_errors and return unless validate_keyrelay_request - abs_datetime = parsed_frame.css('absolute').text - abs_datetime = abs_datetime.to_date if abs_datetime + @domain = find_domain_for_keyrelay - kr = domain.keyrelays.create( - domain: domain, - pa_date: Time.now, - key_data_flags: parsed_frame.css('flags').text, - key_data_protocol: parsed_frame.css('protocol').text, - key_data_alg: parsed_frame.css('alg').text, - key_data_public_key: parsed_frame.css('pubKey').text, - auth_info_pw: parsed_frame.css('pw').text, - expiry_relative: parsed_frame.css('relative').text, - expiry_absolute: abs_datetime, - requester: current_epp_user.registrar, - accepter: domain.registrar - ) - - domain.registrar.messages.create( - body: 'Key Relay action completed successfully.', - attached_obj_type: kr.class.to_s, - attached_obj_id: kr.id - ) + handle_errors(@domain) and return unless @domain + handle_errors(@domain) and return unless @domain.authenticate(parsed_frame.css('pw').text) + handle_errors(@domain) and return unless @domain.keyrelay(parsed_frame, current_epp_user.registrar) render '/epp/shared/success' end + # rubocop: enable Metrics/PerceivedComplexity + # rubocop: enable Metrics/CyclomaticComplexity + + private + + def validate_keyrelay_request + epp_request_valid?('pubKey', 'flags', 'protocol', 'algorithm', 'name', 'pw') + + if parsed_frame.css('relative').text.present? && parsed_frame.css('absolute').text.present? + epp_errors << { + code: '2003', + msg: I18n.t('only_one_parameter_allowed', param_1: 'relative', param_2: 'absolute') + } + elsif parsed_frame.css('relative').text.empty? && parsed_frame.css('absolute').text.empty? + epp_errors << { + code: '2003', + msg: I18n.t('required_parameter_missing_choice', param_1: 'relative', param_2: 'absolute') + } + end + + epp_errors.empty? + end + + def find_domain_for_keyrelay + domain_name = parsed_frame.css('name').text.strip.downcase + domain = Epp::EppDomain.find_by(name: domain_name) + + unless domain + epp_errors << { + code: '2303', + msg: I18n.t('errors.messages.epp_domain_not_found'), + value: { obj: 'name', val: domain_name } + } + return nil + end + + domain + end end diff --git a/app/helpers/epp/poll_helper.rb b/app/helpers/epp/poll_helper.rb index 354455219..7084ac191 100644 --- a/app/helpers/epp/poll_helper.rb +++ b/app/helpers/epp/poll_helper.rb @@ -11,7 +11,12 @@ module Epp::PollHelper if @message.attached_obj_type && @message.attached_obj_id @object = Object.const_get(@message.attached_obj_type).find(@message.attached_obj_id) end - render 'epp/poll/poll_req' + + if @message.attached_obj_type == 'Keyrelay' + render 'epp/poll/poll_keyrelay' + else + render 'epp/poll/poll_req' + end end def ack_poll diff --git a/app/models/epp/epp_domain.rb b/app/models/epp/epp_domain.rb index a7f27314d..ea768824a 100644 --- a/app/models/epp/epp_domain.rb +++ b/app/models/epp/epp_domain.rb @@ -357,6 +357,38 @@ class Epp::EppDomain < Domain save(validate: false) end + def keyrelay(parsed_frame, requester) + if registrar == requester + errors.add(:base, :domain_already_belongs_to_the_querying_registrar) and return false + end + + abs_datetime = parsed_frame.css('absolute').text + abs_datetime = abs_datetime.to_date if abs_datetime + + transaction do + kr = keyrelays.create( + pa_date: Time.now, + key_data_flags: parsed_frame.css('flags').text, + key_data_protocol: parsed_frame.css('protocol').text, + key_data_alg: parsed_frame.css('alg').text, + key_data_public_key: parsed_frame.css('pubKey').text, + auth_info_pw: parsed_frame.css('pw').text, + expiry_relative: parsed_frame.css('relative').text, + expiry_absolute: abs_datetime, + requester: requester, + accepter: registrar + ) + + registrar.messages.create( + body: 'Key Relay action completed successfully.', + attached_obj_type: kr.class.to_s, + attached_obj_id: kr.id + ) + + kr + end + end + ### VALIDATIONS ### def validate_exp_dates(cur_exp_date) diff --git a/app/models/keyrelay.rb b/app/models/keyrelay.rb index e613ddafa..5beb8b77f 100644 --- a/app/models/keyrelay.rb +++ b/app/models/keyrelay.rb @@ -3,4 +3,6 @@ class Keyrelay < ActiveRecord::Base belongs_to :requester, class_name: 'Registrar' belongs_to :accepter, class_name: 'Registrar' + + delegate :name, to: :domain, prefix: true end diff --git a/app/views/epp/poll/poll_keyrelay.xml.builder b/app/views/epp/poll/poll_keyrelay.xml.builder new file mode 100644 index 000000000..2238f5ac4 --- /dev/null +++ b/app/views/epp/poll/poll_keyrelay.xml.builder @@ -0,0 +1,49 @@ +xml.instruct!(:xml, standalone: 'no') +xml.epp( + 'xmlns' => 'urn:ietf:params:xml:ns:epp-1.0', + 'xmlns:secDNS' => 'urn:ietf:params:xml:ns:secDNS-1.1', + 'xmlns:domain' => 'urn:ietf:params:xml:ns:domain-1.0', + 'xmlns:keyrelay' => 'urn:ietf:params:xml:ns:keyrelay-1.0' +) do + xml.response do + xml.result('code' => '1301') do + xml.msg 'Command completed successfully; ack to dequeue' + end + + xml.tag!('msgQ', 'count' => current_epp_user.queued_messages.count, 'id' => @message.id) do + xml.qDate @message.created_at + xml.msg @message.body + end + + xml.resData do + xml.tag!('keyrelay:response') do + xml.tag!('keyrelay:panData') do + xml.tag!('keyrelay:name', @object.domain_name) + xml.tag!('keyrelay:paDate', @object.pa_date) + + xml.tag!('keyrelay:keyData') do + xml.tag!('secDNS:flags', @object.key_data_flags) + xml.tag!('secDNS:protocol', @object.key_data_protocol) + xml.tag!('secDNS:alg', @object.key_data_alg) + xml.tag!('secDNS:pubKey', @object.key_data_public_key) + end + + + xml.tag!('keyrelay:authInfo') do + xml.tag!('domain:pw', @object.auth_info_pw) + end + + xml.tag!('keyrelay:expiry') do + xml.tag!('keyrelay:relative', @object.expiry_relative) + xml.tag!('keyrelay:absolute', @object.expiry_absolute) + end + + xml.tag!('keyrelay:reID', @object.requester) + xml.tag!('keyrelay:acID', @object.accepter) + end + end + end + + xml << render('/epp/shared/trID') + end +end diff --git a/config/locales/en.yml b/config/locales/en.yml index 2d785280d..41f08825b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -426,3 +426,5 @@ en: host_obj_is_not_allowed: 'hostObj object is not allowed' generate_zonefile: 'Generate zonefile' zonefile: 'Zonefile' + only_one_parameter_allowed: 'Only one parameter allowed: %{param_1} or %{param_2}' + required_parameter_missing_choice: 'Required parameter missing: %{param_1} or %{param_2}' diff --git a/spec/epp/keyrelay_spec.rb b/spec/epp/keyrelay_spec.rb index 50696b120..bcdcddd6b 100644 --- a/spec/epp/keyrelay_spec.rb +++ b/spec/epp/keyrelay_spec.rb @@ -39,6 +39,5 @@ describe 'EPP Keyrelay', epp: true do expect(zone.messages.queued.count).to eq(1) end - end end