From 7459d7e0c5b7882a0aa27b58663a8e066da56acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 25 Nov 2020 15:45:43 +0200 Subject: [PATCH 01/80] Nameserver deserializer --- app/controllers/repp/v1/domains_controller.rb | 14 ++++++- app/models/epp/domain.rb | 21 ++--------- config/routes.rb | 2 +- lib/deserializers/xml/nameserver.rb | 37 +++++++++++++++++++ 4 files changed, 53 insertions(+), 21 deletions(-) create mode 100644 lib/deserializers/xml/nameserver.rb diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index ba90f23f2..f69f33dd1 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -1,7 +1,9 @@ +require 'serializers/registrant_api/domain' module Repp module V1 class DomainsController < BaseController - before_action :set_authorized_domain, only: [:transfer_info] + before_action :set_authorized_domain, only: %i[transfer_info] + before_action :set_domain, only: %i[show] def index records = current_user.registrar.domains @@ -11,6 +13,10 @@ module Repp render_success(data: { domains: domains, total_number_of_records: records.count }) end + def show + render_success(data: { domain: Serializers::RegistrantApi::Domain.new(@domain).to_json }) + end + def transfer_info contact_fields = %i[code name ident ident_type ident_country_code phone email street city zip country_code statuses] @@ -66,12 +72,16 @@ module Repp params.permit(:id) end + def set_domain + @domain = Domain.find_by(registrar: current_user.registrar, name: params[:id]) + end + def set_authorized_domain @epp_errors ||= [] h = {} h[transfer_info_params[:id].match?(/\A[0-9]+\z/) ? :id : :name] = transfer_info_params[:id] @domain = Domain.find_by!(h) - + return if @domain.registrar == current_user.registrar return if @domain.transfer_code.eql?(request.headers['Auth-Code']) @epp_errors << { code: 2202, msg: I18n.t('errors.messages.epp_authorization_error') } diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index c46732712..d56fe4e32 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -1,5 +1,5 @@ require 'deserializers/xml/legal_document' - +require 'deserializers/xml/nameserver' class Epp::Domain < Domain include EppErrors @@ -161,7 +161,7 @@ class Epp::Domain < Domain at[:nameservers_attributes] = nameservers_attrs(frame, action) at[:admin_domain_contacts_attributes] = admin_domain_contacts_attrs(frame, action) at[:tech_domain_contacts_attributes] = tech_domain_contacts_attrs(frame, action) - + puts "JHDFHJDGFKDJHF" pw = frame.css('authInfo > pw').text at[:transfer_code] = pw if pw.present? @@ -193,7 +193,7 @@ class Epp::Domain < Domain end def nameservers_attrs(frame, action) - ns_list = nameservers_from(frame) + ns_list = ::Deserializers::Xml::Nameservers.new(frame).call if action == 'rem' to_destroy = [] @@ -215,21 +215,6 @@ class Epp::Domain < Domain end end - def nameservers_from(frame) - res = [] - frame.css('hostAttr').each do |x| - host_attr = { - hostname: x.css('hostName').first.try(:text), - ipv4: x.css('hostAddr[ip="v4"]').map(&:text).compact, - ipv6: x.css('hostAddr[ip="v6"]').map(&:text).compact - } - - res << host_attr.delete_if { |_k, v| v.blank? } - end - - res - end - def admin_domain_contacts_attrs(frame, action) admin_attrs = domain_contact_attrs_from(frame, action, 'admin') diff --git a/config/routes.rb b/config/routes.rb index 0af3d95c9..e2e5bccd5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -59,7 +59,7 @@ Rails.application.routes.draw do end end end - resources :domains do + resources :domains, constraints: { id: /.*/ } do collection do get ':id/transfer_info', to: 'domains#transfer_info', constraints: { id: /.*/ } post 'transfer', to: 'domains#transfer' diff --git a/lib/deserializers/xml/nameserver.rb b/lib/deserializers/xml/nameserver.rb new file mode 100644 index 000000000..f43407d68 --- /dev/null +++ b/lib/deserializers/xml/nameserver.rb @@ -0,0 +1,37 @@ +module Deserializers + module Xml + class Nameserver + attr_reader :frame + + def initialize(frame) + @frame = frame + end + + def call + { + hostname: frame.css('hostName').text, + ipv4: frame.css('hostAddr[ip="v4"]').map(&:text).compact, + ipv6: frame.css('hostAddr[ip="v6"]').map(&:text).compact + } + end + end + + class Nameservers + attr_reader :frame + + def initialize(frame) + @frame = frame + end + + def call + res = [] + frame.css('hostAttr').each do |ns| + ns = Deserializers::Xml::Nameserver.new(ns).call + res << ns.delete_if { |_k, v| v.blank? } + end + + res + end + end + end +end From b683fe813ce99a0f73f7f73824d1e4d5e92a78b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 30 Nov 2020 10:33:23 +0200 Subject: [PATCH 02/80] Implement partial domain deserializer --- lib/deserializers/xml/domain.rb | 49 ++++++++++++++++++++++++++ lib/deserializers/xml/domain_create.rb | 27 ++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 lib/deserializers/xml/domain.rb create mode 100644 lib/deserializers/xml/domain_create.rb diff --git a/lib/deserializers/xml/domain.rb b/lib/deserializers/xml/domain.rb new file mode 100644 index 000000000..f9f893313 --- /dev/null +++ b/lib/deserializers/xml/domain.rb @@ -0,0 +1,49 @@ +module Deserializers + module Xml + class Domain + attr_reader :frame + + def initialize(frame) + @frame = frame + end + + def call + attributes = { + name: if_present('name'), + registrar_id: current_user.registrar.id, + reserved_pw: if_present('reserved > pw'), + period: Integer(frame.css('period').text, 1), + period_unit: parsed_frame.css('period').first ? parsed_frame.css('period').first[:unit] : 'y' + } + + pw = frame.css('authInfo > pw').text + attributes[:transfer_code] = pw if pw.present? + attributes.compact + end + + def if_present(css_path) + return if frame.css(css_path).blank? + + frame.css(css_path).text + end + + def statuses_to_add + statuses_frame = frame.css('add') + return if statuses_frame.blank? + + statuses_frame.css('status').map do |status| + status['s'] + end + end + + def statuses_to_remove + statuses_frame = frame.css('rem') + return if statuses_frame.blank? + + statuses_frame.css('status').map do |status| + status['s'] + end + end + end + end +end diff --git a/lib/deserializers/xml/domain_create.rb b/lib/deserializers/xml/domain_create.rb new file mode 100644 index 000000000..b3bc6fe4a --- /dev/null +++ b/lib/deserializers/xml/domain_create.rb @@ -0,0 +1,27 @@ +require 'deserializers/xml/legal_document' +require 'deserializers/xml/ident' +require 'deserializers/xml/contact' + +module Deserializers + module Xml + class ContactUpdate + attr_reader :frame + + def initialize(frame) + @frame = frame + end + + def contact + @contact ||= ::Deserializers::Xml::Contact.new(frame).call + end + + def ident + @ident ||= ::Deserializers::Xml::Ident.new(frame).call + end + + def legal_document + @legal_document ||= ::Deserializers::Xml::LegalDocument.new(frame).call + end + end + end +end From ccef1053d9fde039b4bfbce41deb86f3d58027a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 8 Dec 2020 12:00:04 +0200 Subject: [PATCH 03/80] Create DomainCreate action --- app/controllers/epp/domains_controller.rb | 4 + app/models/actions/domain_create.rb | 134 ++++++++++++++++++++++ app/models/epp/domain.rb | 28 ++--- lib/deserializers/xml/dnssec.rb | 89 ++++++++++++++ lib/deserializers/xml/domain.rb | 11 +- lib/deserializers/xml/domain_create.rb | 42 +++++-- 6 files changed, 280 insertions(+), 28 deletions(-) create mode 100644 app/models/actions/domain_create.rb create mode 100644 lib/deserializers/xml/dnssec.rb diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index d9a8b2b5d..9e21650cf 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -28,6 +28,10 @@ module Epp def create authorize! :create, Epp::Domain + domain_params = ::Deserializers::Xml::DomainCreate.new(params[:parsed_frame], current_user.registrar.id) + puts "Ayy lmao" + puts domain_params.call + if Domain.release_to_auction request_domain_name = params[:parsed_frame].css('name').text.strip.downcase domain_name = DNS::DomainName.new(SimpleIDN.to_unicode(request_domain_name)) diff --git a/app/models/actions/domain_create.rb b/app/models/actions/domain_create.rb new file mode 100644 index 000000000..2dd2b7d2a --- /dev/null +++ b/app/models/actions/domain_create.rb @@ -0,0 +1,134 @@ +module Actions + class DomainCreate + attr_reader :domain, :params + + def initialize(domain, params) + @domain = domain + @params = params + end + + def call + validate_domain_integrity + assign_registrant + assign_domain_attributes + assign_nameservers + assign_admin_contacts + assign_tech_contacts + assign_expiry_time + + return domain unless domain.save + + commit + end + + # Check if domain is eligible for new registration + def validate_domain_integrity + return if Domain.release_to_auction + + dn = DNS::DomainName.new(SimpleIDN.to_unicode(params[:name])) + domain.add_epp_error(2306, nil, nil, 'Parameter value policy error: domain is at auction') if dn.at_auction? + domain.add_epp_error(2003, nil, nil, 'Required parameter missing; reserved>pw element required for reserved domains') if dn.awaiting_payment? + return unless dn.pending_registration? + + domain.add_epp_error(2003, nil, nil, 'Required parameter missing; reserved>pw element is required') if params[:reserved_pw].empty? + domain.add_epp_errpr(2202, nil, nil, 'Invalid authorization information; invalid reserved>pw value') unless dn.available_with_code?(params[:reserved_pw]) + end + + def assign_registrant + domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) and return unless params[:registrant_id] + + regt = Registrant.find_by(code: params[:registrant_id]) + domain.add_epp_error('2303', 'registrant', code, %i[registrant not_found]) and return unless regt + + domain.registrant = regt + end + + def assign_domain_attributes + domain.name = params[:name] + domain.registrar = Registrar.find(params[:registrar_id]) + domain.period = params[:period] + domain.period_unit = params[:period_unit] + domain.reserved_pw = params[:reserved_pw] if params[:transfer_code] + domain.transfer_code = params[:transfer_code] if params[:transfer_code] + domain.dnskeys_attributes = params[:dnskeys_attributes] + end + + def assign_nameservers + domain.nameservers_attributes = params[:nameservers_attributes] + end + + def assign_admin_contacts + attrs = [] + params[:admin_domain_contacts_attributes].each do |c| + contact = Contact.find_by(code: c) + domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) unless contact + attrs << { contact_id: contact.id, contact_code_cache: contact.code } if contact + end + + domain.admin_domain_contacts_attributes = attrs + end + + def assign_tech_contacts + attrs = [] + params[:tech_domain_contacts_attributes].each do |c| + contact = Contact.find_by(code: c) + domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) unless contact + attrs << { contact_id: contact.id, contact_code_cache: contact.code } if contact + end + + domain.tech_domain_contacts_attributes = attrs + end + + def assign_expiry_time + period = domain.period.to_i + plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym + expire_time = (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day + domain.expire_time = expire_time + end + + def debit_registrar + domain_pricelist = domain.pricelist('create', domain.period.try(:to_i), domain.period_unit) + if @domain_pricelist.try(:price) && domain.registrar.balance < domain_pricelist.price.amount + domain.add_epp_error(2104, nil, nil, I18n.t('billing_failure_credit_balance_low')) + return + elsif !@domain_pricelist.try(:price) + domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) + return + end + + domain.registrar.debit!({ sum: @domain_pricelist.price.amount, price: @domain_pricelist, + description: "#{I18n.t('create')} #{@domain.name}", + activity_type: AccountActivity::CREATE }) + end + + def process_auction_and_disputes + dn = DNS::DomainName.new(SimpleIDN.to_unicode(domain.name)) + Dispute.close_by_domain(domain.name) + return unless Domain.release_to_auction && dn.pending_registration? + + auction = Auction.find_by(domain: domain.name, status: Auction.statuses[:payment_received]) + auction.domain_registered! + end + + def maybe_attach_legal_doc + return unless legal_document + + doc = LegalDocument.create( + documentable_type: Contact, + document_type: legal_document[:type], body: legal_document[:body] + ) + + contact.legal_documents = [doc] + contact.legal_document_id = doc.id + end + + def commit + ActiveRecord::Base.transaction do + debit_registrar + process_auction_and_disputes + + domain.save + end + end + end +end diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index d56fe4e32..2d5718b43 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -1,5 +1,6 @@ require 'deserializers/xml/legal_document' require 'deserializers/xml/nameserver' +require 'deserializers/xml/domain_create' class Epp::Domain < Domain include EppErrors @@ -38,6 +39,10 @@ class Epp::Domain < Domain class << self def new_from_epp(frame, current_user) + domain_create = ::Deserializers::Xml::DomainCreate.new(frame, current_user.registrar.id) + puts "DOMAIN CREATE ACTION" + puts domain_create + domain = Epp::Domain.new domain.attributes = domain.attrs_from(frame, current_user) domain.attach_default_contacts @@ -147,23 +152,19 @@ class Epp::Domain < Domain end if registrant_frame - at[:name] = frame.css('name').text if new_record? - at[:registrar_id] = current_user.registrar.try(:id) - - period = frame.css('period').text - at[:period] = (period.to_i == 0) ? 1 : period.to_i - - at[:period_unit] = Epp::Domain.parse_period_unit_from_frame(frame) || 'y' - - at[:reserved_pw] = frame.css('reserved > pw').text - + at[:name] = frame.css('name').text if new_record? # Done + at[:registrar_id] = current_user.registrar.try(:id) # Done + period = frame.css('period').text # Done + at[:period] = (period.to_i == 0) ? 1 : period.to_i # Done + at[:period_unit] = Epp::Domain.parse_period_unit_from_frame(frame) || 'y' # Done + at[:reserved_pw] = frame.css('reserved > pw').text # Done + pw = frame.css('authInfo > pw').text # Done + at[:transfer_code] = pw if pw.present? # Done # at[:statuses] = domain_statuses_attrs(frame, action) + at[:nameservers_attributes] = nameservers_attrs(frame, action) at[:admin_domain_contacts_attributes] = admin_domain_contacts_attrs(frame, action) at[:tech_domain_contacts_attributes] = tech_domain_contacts_attrs(frame, action) - puts "JHDFHJDGFKDJHF" - pw = frame.css('authInfo > pw').text - at[:transfer_code] = pw if pw.present? if new_record? dnskey_frame = frame.css('extension create') @@ -315,6 +316,7 @@ class Epp::Domain < Domain add_epp_error('2303', nil, nil, [:dnskeys, :not_found]) if keys.include? nil end end + errors.any? ? [] : keys end diff --git a/lib/deserializers/xml/dnssec.rb b/lib/deserializers/xml/dnssec.rb new file mode 100644 index 000000000..203e13197 --- /dev/null +++ b/lib/deserializers/xml/dnssec.rb @@ -0,0 +1,89 @@ +module Deserializers + module Xml + class DnssecKey + attr_reader :frame, :dsa + + KEY_INTERFACE = { flags: 'flags', protocol: 'protocol', alg: 'alg', public_key: 'pubKey' } + DS_INTERFACE = { ds_key_tag: 'keyTag', ds_alg: 'alg', ds_digest_type: 'digestType', + ds_digest: 'digest' } + + def initialize(frame, dsa) + @frame = frame + @dsa = dsa + end + + def call + dsa ? ds_alg_output : xm_copy(frame, KEY_INTERFACE) + end + + def ds_alg_output + ds_key = xm_copy(frame, DS_INTERFACE) + ds_key.merge(xm_copy(frame.css('keyData'), KEY_INTERFACE)) if frame.css('keyData').present? + ds_key + end + + def other_alg_output + xm_copy(frame, KEY_INTERFACE) + end + + private + + def xm_copy(entry, map) + result = {} + map.each do |key, elem| + result[key] = entry.css(elem).first.try(:text) + end + result + end + end + + class DnssecKeys + attr_reader :frame, :key_data, :ds_data + + def initialize(frame) + @key_data = [] + @ds_data = [] + + # schema validation prevents both in the same parent node + if frame.css('dsData').present? + frame.css('dsData').each do |ds_data| + @ds_data << Deserializers::Xml::DnssecKey.new(ds_data, true).call + end + else + frame.css('keyData').each do |key| + @key_data << Deserializers::Xml::DnssecKey.new(key, false).call + end + end + end + + def mark_destroy_all(dns_keys) + # if transition support required mark_destroy dns_keys when has ds/key values otherwise ... + dns_keys.map { |inf_data| mark(inf_data) } + end + + def mark_destroy(dns_keys) + (ds_data.present? ? ds_filter(dns_keys) : kd_filter(dns_keys)).map do |inf_data| + inf_data.blank? ? nil : mark(inf_data) + end + end + + private + + def ds_filter(dns_keys) + @ds_data.map do |ds| + dns_keys.find_by(ds.slice(*DS_INTERFACE.keys)) + end + end + + def kd_filter(dns_keys) + @key_data.map do |key| + dns_keys.find_by(key) + end + end + + def mark(inf_data) + { id: inf_data.id, _destroy: 1 } + end + end + end +end diff --git a/lib/deserializers/xml/domain.rb b/lib/deserializers/xml/domain.rb index f9f893313..74683761c 100644 --- a/lib/deserializers/xml/domain.rb +++ b/lib/deserializers/xml/domain.rb @@ -2,18 +2,21 @@ module Deserializers module Xml class Domain attr_reader :frame + attr_reader :registrar - def initialize(frame) + def initialize(frame, registrar) @frame = frame + @registrar = registrar end def call attributes = { name: if_present('name'), - registrar_id: current_user.registrar.id, + registrar_id: registrar, + registrant_id: if_present('registrant'), reserved_pw: if_present('reserved > pw'), - period: Integer(frame.css('period').text, 1), - period_unit: parsed_frame.css('period').first ? parsed_frame.css('period').first[:unit] : 'y' + period: Integer(frame.css('period').text) || 1, + period_unit: frame.css('period').first ? frame.css('period').first[:unit] : 'y', } pw = frame.css('authInfo > pw').text diff --git a/lib/deserializers/xml/domain_create.rb b/lib/deserializers/xml/domain_create.rb index b3bc6fe4a..51a98bd23 100644 --- a/lib/deserializers/xml/domain_create.rb +++ b/lib/deserializers/xml/domain_create.rb @@ -1,26 +1,46 @@ require 'deserializers/xml/legal_document' -require 'deserializers/xml/ident' -require 'deserializers/xml/contact' - +require 'deserializers/xml/domain' +require 'deserializers/xml/nameserver' +require 'deserializers/xml/dnssec' module Deserializers module Xml - class ContactUpdate + class DomainCreate attr_reader :frame + attr_reader :registrar - def initialize(frame) + def initialize(frame, registrar) @frame = frame + @registrar = registrar end - def contact - @contact ||= ::Deserializers::Xml::Contact.new(frame).call + def call + obj = domain + obj[:admin_domain_contacts_attributes] = admin_contacts + obj[:tech_domain_contacts_attributes] = tech_contacts + obj[:nameservers_attributes] = nameservers + obj[:dnskeys_attributes] = dns_keys + + obj end - def ident - @ident ||= ::Deserializers::Xml::Ident.new(frame).call + def domain + @domain ||= ::Deserializers::Xml::Domain.new(frame, registrar).call end - def legal_document - @legal_document ||= ::Deserializers::Xml::LegalDocument.new(frame).call + def nameservers + @nameservers ||= ::Deserializers::Xml::Nameservers.new(frame).call + end + + def admin_contacts + frame.css('contact').map { |c| c.text if c['type'] == 'admin' } + end + + def tech_contacts + frame.css('contact').map { |c| c.text if c['type'] == 'tech' } + end + + def dns_keys + @dns_keys ||= ::Deserializers::Xml::DnssecKeys.new(frame).key_data end end end From ad2ccdba7ddd035e2c146dd73c56a0eef20f9894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 8 Dec 2020 18:06:48 +0200 Subject: [PATCH 04/80] Improve DomainCreate wrapper for EPP --- app/controllers/epp/domains_controller.rb | 80 ++----------------- app/models/actions/domain_create.rb | 69 +++++++++------- app/models/epp/domain.rb | 19 ----- lib/deserializers/xml/domain.rb | 2 +- lib/deserializers/xml/domain_create.rb | 4 +- .../repp/v1/domains/transfer_info_test.rb | 1 + .../repp/v1/retained_domains_test.rb | 2 +- 7 files changed, 53 insertions(+), 124 deletions(-) diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index 9e21650cf..a8ce3f382 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -26,82 +26,14 @@ module Epp end def create - authorize! :create, Epp::Domain + authorize!(:create, Epp::Domain) - domain_params = ::Deserializers::Xml::DomainCreate.new(params[:parsed_frame], current_user.registrar.id) - puts "Ayy lmao" - puts domain_params.call + registrar_id = current_user.registrar.id + @domain = Epp::Domain.new + data = ::Deserializers::Xml::DomainCreate.new(params[:parsed_frame], registrar_id).call + action = Actions::DomainCreate.new(@domain, data) - if Domain.release_to_auction - request_domain_name = params[:parsed_frame].css('name').text.strip.downcase - domain_name = DNS::DomainName.new(SimpleIDN.to_unicode(request_domain_name)) - - if domain_name.at_auction? - epp_errors << { - code: '2306', - msg: 'Parameter value policy error: domain is at auction', - } - handle_errors - return - elsif domain_name.awaiting_payment? - 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? - 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) - epp_errors << { - code: '2202', - msg: 'Invalid authorization information; invalid reserved>pw value', - } - handle_errors - return - end - end - end - - @domain = Epp::Domain.new_from_epp(params[:parsed_frame], current_user) - handle_errors(@domain) and return if @domain.errors.any? - @domain.valid? - @domain.errors.delete(:name_dirty) if @domain.errors[:puny_label].any? - handle_errors(@domain) and return if @domain.errors.any? - handle_errors and return unless balance_ok?('create') # loads pricelist in this method - - ActiveRecord::Base.transaction do - @domain.add_legal_file_to_new(params[:parsed_frame]) - - if @domain.save # TODO: Maybe use validate: false here because we have already validated the domain? - current_user.registrar.debit!({ - sum: @domain_pricelist.price.amount, - description: "#{I18n.t('create')} #{@domain.name}", - activity_type: AccountActivity::CREATE, - price: @domain_pricelist - }) - - if Domain.release_to_auction && domain_name.pending_registration? - active_auction = Auction.find_by(domain: domain_name.to_s, - status: Auction.statuses[:payment_received]) - active_auction.domain_registered! - end - Dispute.close_by_domain(@domain.name) - render_epp_response '/epp/domains/create' - else - handle_errors(@domain) - end - end + action.call ? render_epp_response('/epp/domains/create') : handle_errors(@domain) end def update diff --git a/app/models/actions/domain_create.rb b/app/models/actions/domain_create.rb index 2dd2b7d2a..6ad79544d 100644 --- a/app/models/actions/domain_create.rb +++ b/app/models/actions/domain_create.rb @@ -8,48 +8,58 @@ module Actions end def call - validate_domain_integrity - assign_registrant assign_domain_attributes + validate_domain_integrity + return false if domain.errors[:epp_errors].any? + + assign_registrant assign_nameservers assign_admin_contacts assign_tech_contacts + domain.attach_default_contacts assign_expiry_time - return domain unless domain.save - commit end # Check if domain is eligible for new registration def validate_domain_integrity - return if Domain.release_to_auction + return unless Domain.release_to_auction - dn = DNS::DomainName.new(SimpleIDN.to_unicode(params[:name])) - domain.add_epp_error(2306, nil, nil, 'Parameter value policy error: domain is at auction') if dn.at_auction? - domain.add_epp_error(2003, nil, nil, 'Required parameter missing; reserved>pw element required for reserved domains') if dn.awaiting_payment? - return unless dn.pending_registration? - - domain.add_epp_error(2003, nil, nil, 'Required parameter missing; reserved>pw element is required') if params[:reserved_pw].empty? - domain.add_epp_errpr(2202, nil, nil, 'Invalid authorization information; invalid reserved>pw value') unless dn.available_with_code?(params[:reserved_pw]) + dn = DNS::DomainName.new(SimpleIDN.to_unicode(params[:name].strip.downcase)) + if dn.at_auction? + domain.add_epp_error('2306', nil, nil, 'Parameter value policy error: domain is at auction') + return + elsif dn.awaiting_payment? + domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw element required for reserved domains') + return + elsif dn.pending_registration? + if params[:reserved_pw].blank? + domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw element is required') + else + unless dn.available_with_code?(params[:reserved_pw]) + domain.add_epp_error('2202', nil, nil, 'Invalid authorization information; invalid reserved>pw value') + end + end + end end def assign_registrant domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) and return unless params[:registrant_id] regt = Registrant.find_by(code: params[:registrant_id]) - domain.add_epp_error('2303', 'registrant', code, %i[registrant not_found]) and return unless regt + domain.add_epp_error('2303', 'registrant', params[:registrant_id], %i[registrant not_found]) and return unless regt domain.registrant = regt end def assign_domain_attributes - domain.name = params[:name] + domain.name = params[:name].strip.downcase domain.registrar = Registrar.find(params[:registrar_id]) domain.period = params[:period] domain.period_unit = params[:period_unit] - domain.reserved_pw = params[:reserved_pw] if params[:transfer_code] - domain.transfer_code = params[:transfer_code] if params[:transfer_code] + domain.transfer_code = params[:transfer_code] if params[:transfer_code].present? + domain.reserved_pw = params[:reserved_pw] if params[:reserved_pw].present? domain.dnskeys_attributes = params[:dnskeys_attributes] end @@ -61,7 +71,7 @@ module Actions attrs = [] params[:admin_domain_contacts_attributes].each do |c| contact = Contact.find_by(code: c) - domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) unless contact + domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) unless contact.present? attrs << { contact_id: contact.id, contact_code_cache: contact.code } if contact end @@ -72,7 +82,7 @@ module Actions attrs = [] params[:tech_domain_contacts_attributes].each do |c| contact = Contact.find_by(code: c) - domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) unless contact + domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) unless contact.present? attrs << { contact_id: contact.id, contact_code_cache: contact.code } if contact end @@ -87,8 +97,8 @@ module Actions end def debit_registrar - domain_pricelist = domain.pricelist('create', domain.period.try(:to_i), domain.period_unit) - if @domain_pricelist.try(:price) && domain.registrar.balance < domain_pricelist.price.amount + @domain_pricelist ||= domain.pricelist('create', domain.period.try(:to_i), domain.period_unit) + if @domain_pricelist.try(:price) && domain.registrar.balance < @domain_pricelist.price.amount domain.add_epp_error(2104, nil, nil, I18n.t('billing_failure_credit_balance_low')) return elsif !@domain_pricelist.try(:price) @@ -97,12 +107,12 @@ module Actions end domain.registrar.debit!({ sum: @domain_pricelist.price.amount, price: @domain_pricelist, - description: "#{I18n.t('create')} #{@domain.name}", + description: "#{I18n.t('create')} #{domain.name}", activity_type: AccountActivity::CREATE }) end def process_auction_and_disputes - dn = DNS::DomainName.new(SimpleIDN.to_unicode(domain.name)) + dn = DNS::DomainName.new(SimpleIDN.to_unicode(params[:name])) Dispute.close_by_domain(domain.name) return unless Domain.release_to_auction && dn.pending_registration? @@ -123,12 +133,17 @@ module Actions end def commit - ActiveRecord::Base.transaction do - debit_registrar - process_auction_and_disputes - - domain.save + unless domain.valid? + domain.errors.delete(:name_dirty) if domain.errors[:puny_label].any? + return false if domain.errors.any? end + # @domain.add_legal_file_to_new(params[:parsed_frame]) + debit_registrar + + return false if domain.errors.any? + + process_auction_and_disputes + domain.save end end end diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 2d5718b43..442b37102 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -37,25 +37,6 @@ class Epp::Domain < Domain ok end - class << self - def new_from_epp(frame, current_user) - domain_create = ::Deserializers::Xml::DomainCreate.new(frame, current_user.registrar.id) - puts "DOMAIN CREATE ACTION" - puts domain_create - - domain = Epp::Domain.new - domain.attributes = domain.attrs_from(frame, current_user) - domain.attach_default_contacts - - period = domain.period.to_i - plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym - expire_time = (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day - domain.expire_time = expire_time - - domain - end - end - def epp_code_map { '2002' => [ # Command use error diff --git a/lib/deserializers/xml/domain.rb b/lib/deserializers/xml/domain.rb index 74683761c..7b8ba3097 100644 --- a/lib/deserializers/xml/domain.rb +++ b/lib/deserializers/xml/domain.rb @@ -15,7 +15,7 @@ module Deserializers registrar_id: registrar, registrant_id: if_present('registrant'), reserved_pw: if_present('reserved > pw'), - period: Integer(frame.css('period').text) || 1, + period: frame.css('period').text.present? ? Integer(frame.css('period').text) : 1, period_unit: frame.css('period').first ? frame.css('period').first[:unit] : 'y', } diff --git a/lib/deserializers/xml/domain_create.rb b/lib/deserializers/xml/domain_create.rb index 51a98bd23..d1d621573 100644 --- a/lib/deserializers/xml/domain_create.rb +++ b/lib/deserializers/xml/domain_create.rb @@ -32,11 +32,11 @@ module Deserializers end def admin_contacts - frame.css('contact').map { |c| c.text if c['type'] == 'admin' } + frame.css('contact').select { |c| c['type'] == 'admin' }.map(&:text) end def tech_contacts - frame.css('contact').map { |c| c.text if c['type'] == 'tech' } + frame.css('contact').select { |c| c['type'] == 'tech' }.map(&:text) end def dns_keys diff --git a/test/integration/repp/v1/domains/transfer_info_test.rb b/test/integration/repp/v1/domains/transfer_info_test.rb index f57675b06..5bbfca1a6 100644 --- a/test/integration/repp/v1/domains/transfer_info_test.rb +++ b/test/integration/repp/v1/domains/transfer_info_test.rb @@ -28,6 +28,7 @@ class ReppV1DomainsTransferInfoTest < ActionDispatch::IntegrationTest def test_respects_domain_authorization_code headers = @auth_headers headers['Auth-Code'] = 'jhfgifhdg' + @domain.update!(registrar: registrars(:goodnames)) get "/repp/v1/domains/#{@domain.name}/transfer_info", headers: headers json = JSON.parse(response.body, symbolize_names: true) diff --git a/test/integration/repp/v1/retained_domains_test.rb b/test/integration/repp/v1/retained_domains_test.rb index 1c9f49f58..73b32d381 100644 --- a/test/integration/repp/v1/retained_domains_test.rb +++ b/test/integration/repp/v1/retained_domains_test.rb @@ -77,7 +77,7 @@ class ReppV1RetainedDomainsTest < ActionDispatch::IntegrationTest status: 'disputed', punycode_name: 'reserved.test' }] - assert_equal response_json[:domains], expected_objects + assert_equal response_json[:domains].to_set, expected_objects.to_set end def test_etags_cache From 2c8a4d3fe92a9717131ce80e3be5882fd9049464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 8 Dec 2020 18:13:11 +0200 Subject: [PATCH 05/80] Fix some styling issues --- app/models/actions/domain_create.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/models/actions/domain_create.rb b/app/models/actions/domain_create.rb index 6ad79544d..9cff3ce17 100644 --- a/app/models/actions/domain_create.rb +++ b/app/models/actions/domain_create.rb @@ -29,10 +29,8 @@ module Actions dn = DNS::DomainName.new(SimpleIDN.to_unicode(params[:name].strip.downcase)) if dn.at_auction? domain.add_epp_error('2306', nil, nil, 'Parameter value policy error: domain is at auction') - return elsif dn.awaiting_payment? domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw element required for reserved domains') - return elsif dn.pending_registration? if params[:reserved_pw].blank? domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw element is required') From e81653a0b4ff7b8e7b5b7d9942b3fbce9b3b9d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 9 Dec 2020 15:03:40 +0200 Subject: [PATCH 06/80] Create deserializer for EPP DomainUpdate --- lib/deserializers/xml/dnssec.rb | 4 ++ lib/deserializers/xml/domain_update.rb | 76 ++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 lib/deserializers/xml/domain_update.rb diff --git a/lib/deserializers/xml/dnssec.rb b/lib/deserializers/xml/dnssec.rb index 203e13197..f255716d4 100644 --- a/lib/deserializers/xml/dnssec.rb +++ b/lib/deserializers/xml/dnssec.rb @@ -56,6 +56,10 @@ module Deserializers end end + def call + key_data + ds_data + end + def mark_destroy_all(dns_keys) # if transition support required mark_destroy dns_keys when has ds/key values otherwise ... dns_keys.map { |inf_data| mark(inf_data) } diff --git a/lib/deserializers/xml/domain_update.rb b/lib/deserializers/xml/domain_update.rb new file mode 100644 index 000000000..f89eef8f2 --- /dev/null +++ b/lib/deserializers/xml/domain_update.rb @@ -0,0 +1,76 @@ +require 'deserializers/xml/legal_document' +require 'deserializers/xml/domain' +require 'deserializers/xml/nameserver' +require 'deserializers/xml/dnssec' +module Deserializers + module Xml + class DomainUpdate + attr_reader :frame, :registrar + + def initialize(frame, registrar) + @frame = frame + @registrar = registrar + end + + def call + obj = { domain: frame.css('name')&.text, registrant: registrant, contacts: contacts, + auth_info: if_present('pw'), nameservers: nameservers, dns_keys: dns_keys } + + obj.reject { |_key, val| val.blank? } + end + + def registrant + return if frame.css('chg > registrant').blank? + + { code: frame.css('chg > registrant').text, verified: frame.css('chg > registrant').attr('verified').to_s.downcase == 'yes' } + end + + def contacts + contacts = [] + frame.css('add > contact').each do |c| + contacts << { code: c.text, type: c['type'], action: 'add' } + end + + frame.css('rem > contact').each do |c| + contacts << { code: c.text, type: c['type'], action: 'rem' } + end + + contacts.present? ? contacts : nil + end + + def nameservers + nameservers = [] + frame.css('add > ns > hostAttr').each do |ns| + nsrv = { nameserver: ns.css('hostName').text, host_addr: [], action: 'add' } + ns.css('hostAddr').each { |ha| nsrv[:host_addr] << { proto: ha.attr('ip').to_s.downcase, addr: ha.text } } + nameservers << nsrv + end + + frame.css('rem > ns > hostAttr').each do |ns| + nsrv = { nameserver: ns.css('hostName').text, host_addr: [], action: 'rem' } + ns.css('hostAddr').each { |ha| nsrv[:host_addr] << { proto: ha.attr('ip').to_s.downcase, addr: ha.text } } + nameservers << nsrv + end + + nameservers.present? ? nameservers : nil + end + + def dns_keys + added = ::Deserializers::Xml::DnssecKeys.new(frame.css('add')).call + added.each { |k| k[:action] = 'add' } + removed = ::Deserializers::Xml::DnssecKeys.new(frame.css('rem')).call + removed.each { |k| k[:action] = 'rem' } + + return unless (added + removed).present? + + added + removed + end + + def if_present(css_path) + return if frame.css(css_path).blank? + + frame.css(css_path).text + end + end + end +end From 096289abccfb9dcdc7fc7725ffc4feb33ac90b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 9 Dec 2020 17:20:46 +0200 Subject: [PATCH 07/80] Implement partial DomainUpdate action --- app/models/actions/domain_update.rb | 194 ++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 app/models/actions/domain_update.rb diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb new file mode 100644 index 000000000..da64f3df8 --- /dev/null +++ b/app/models/actions/domain_update.rb @@ -0,0 +1,194 @@ +module Actions + class DomainCreate + attr_reader :domain, :params + + def initialize(domain, params) + @domain = domain + @params = params + end + + def call + validate_domain_integrity + verify_registrant_change # Should be last step + assign_admin_contact_changes if params[:contacts] + assign_tech_contact_changes if params[:contacts] + end + + def validate_domain_integrity + return unless domain.discarded? + + domain.add_epp_error('2304', nil, nil, 'Object status prohibits operation') + end + + def assign_admin_contact_changes + props = [] + contacts = params[:contacts].select { |c| c[:type] == 'admin' } + + if contacts.present? && domain.admin_change_prohibited? + domain.add_epp_error('2304', 'admin', DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) + return + end + + contacts.select { |c| c[:action] == 'rem' }.each do |c| + dc = domain.admin_domain_contacts.find_by(contact_code_cache: c[:code]) + domain.add_epp_error('2303', 'contact', at[:contact_code_cache], [:domain_contacts, :not_found]) and break unless dc + + props << { id: dc.id, _destroy: 1 } + end + + contacts.select { |c| c[:action] == 'add' }.each do |c| + contact = Epp::Contact.find_by_epp_code(c[:code]) + domain.add_epp_error('2303', 'contact', c[:code], [:domain_contacts, :not_found]) and break unless contact + domain.add_epp_error('2306', 'contact', c[:code], [:domain_contacts, :admin_contact_can_be_only_private_person]) and break if contact.org? + + props << { id: contact.id, code: contact.code } + end + + domain.admin_domain_contacts_attributes = props + end + + def assign_tech_contact_changes + props = [] + contacts = params[:contacts].select { |c| c[:type] == 'admin' } + + if contacts.present? && domain.admin_change_prohibited? + domain.add_epp_error('2304', 'admin', DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) + return + end + + contacts.select { |c| c[:action] == 'rem' }.each do |c| + dc = domain.admin_domain_contacts.find_by(contact_code_cache: c[:code]) + domain.add_epp_error('2303', 'contact', at[:contact_code_cache], [:domain_contacts, :not_found]) and break unless dc + + props << { id: dc.id, _destroy: 1 } + end + + contacts.select { |c| c[:action] == 'add' }.each do |c| + contact = Epp::Contact.find_by_epp_code(c[:code]) + domain.add_epp_error('2303', 'contact', c[:code], [:domain_contacts, :not_found]) and break unless contact + domain.add_epp_error('2306', 'contact', c[:code], [:domain_contacts, :admin_contact_can_be_only_private_person]) and break if contact.org? + + props << { id: contact.id, code: contact.code } + end + + domain.admin_domain_contacts_attributes = props + end + + def verify_registrant_change + return if !params[:registrant] || domain.registrant.code == params[:registrant][:code] + + if domain.disputed? + domain.add_epp_error('2304', nil, nil, 'Required parameter missing; reservedpw element required for dispute domains') and return unless params[:reserved_pw] + dispute = Dispute.active.find_by(domain_name: name, password: params[:reserved_pw]) + domain.add_epp_error('2202', nil, nil, 'Invalid authorization information; invalid reserved>pw value') and return unless dispute + Dispute.close_by_domain(name) + end + + return unless params[:registrant][:verified] && Setting.request_confirmation_on_registrant_change_enabled + + domain.registrant_verification_asked!(frame.to_s, current_user.id) + end + + def assign_registrant + domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) and return unless params[:registrant_id] + + regt = Registrant.find_by(code: params[:registrant_id]) + domain.add_epp_error('2303', 'registrant', params[:registrant_id], %i[registrant not_found]) and return unless regt + + domain.registrant = regt + end + + def assign_domain_attributes + domain.name = params[:name].strip.downcase + domain.registrar = Registrar.find(params[:registrar_id]) + domain.period = params[:period] + domain.period_unit = params[:period_unit] + domain.transfer_code = params[:transfer_code] if params[:transfer_code].present? + domain.reserved_pw = params[:reserved_pw] if params[:reserved_pw].present? + domain.dnskeys_attributes = params[:dnskeys_attributes] + end + + def assign_nameservers + domain.nameservers_attributes = params[:nameservers_attributes] + end + + def assign_admin_contacts + attrs = [] + params[:admin_domain_contacts_attributes].each do |c| + contact = Contact.find_by(code: c) + domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) unless contact.present? + attrs << { contact_id: contact.id, contact_code_cache: contact.code } if contact + end + + domain.admin_domain_contacts_attributes = attrs + end + + def assign_tech_contacts + attrs = [] + params[:tech_domain_contacts_attributes].each do |c| + contact = Contact.find_by(code: c) + domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) unless contact.present? + attrs << { contact_id: contact.id, contact_code_cache: contact.code } if contact + end + + domain.tech_domain_contacts_attributes = attrs + end + + def assign_expiry_time + period = domain.period.to_i + plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym + expire_time = (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day + domain.expire_time = expire_time + end + + def debit_registrar + @domain_pricelist ||= domain.pricelist('create', domain.period.try(:to_i), domain.period_unit) + if @domain_pricelist.try(:price) && domain.registrar.balance < @domain_pricelist.price.amount + domain.add_epp_error(2104, nil, nil, I18n.t('billing_failure_credit_balance_low')) + return + elsif !@domain_pricelist.try(:price) + domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) + return + end + + domain.registrar.debit!({ sum: @domain_pricelist.price.amount, price: @domain_pricelist, + description: "#{I18n.t('create')} #{domain.name}", + activity_type: AccountActivity::CREATE }) + end + + def process_auction_and_disputes + dn = DNS::DomainName.new(SimpleIDN.to_unicode(params[:name])) + Dispute.close_by_domain(domain.name) + return unless Domain.release_to_auction && dn.pending_registration? + + auction = Auction.find_by(domain: domain.name, status: Auction.statuses[:payment_received]) + auction.domain_registered! + end + + def maybe_attach_legal_doc + return unless legal_document + + doc = LegalDocument.create( + documentable_type: Contact, + document_type: legal_document[:type], body: legal_document[:body] + ) + + contact.legal_documents = [doc] + contact.legal_document_id = doc.id + end + + def commit + unless domain.valid? + domain.errors.delete(:name_dirty) if domain.errors[:puny_label].any? + return false if domain.errors.any? + end + # @domain.add_legal_file_to_new(params[:parsed_frame]) + debit_registrar + + return false if domain.errors.any? + + process_auction_and_disputes + domain.save + end + end +end From 766d843597a65ab1121230625d380824b78ccd8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 15 Dec 2020 13:27:20 +0200 Subject: [PATCH 08/80] Improve DomainUpdate logic --- app/controllers/epp/domains_controller.rb | 16 +- app/models/actions/domain_update.rb | 247 ++++++++++++---------- app/models/epp/domain.rb | 6 +- lib/deserializers/xml/domain_update.rb | 22 +- 4 files changed, 165 insertions(+), 126 deletions(-) diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index a8ce3f382..3432f8953 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -37,13 +37,17 @@ module Epp end def update - authorize! :update, @domain, @password + authorize!(:update, @domain, @password) - updated = @domain.update(params[:parsed_frame], current_user) - (handle_errors(@domain) && return) unless updated - - pending = @domain.epp_pending_update.present? - render_epp_response "/epp/domains/success#{'_pending' if pending}" + registrar_id = current_user.registrar.id + update_params = ::Deserializers::Xml::DomainUpdate.new(params[:parsed_frame], registrar_id).call + action = Actions::DomainUpdate.new(@domain, update_params, false) + if action.call + pending = @domain.epp_pending_update.present? + render_epp_response("/epp/domains/success#{'_pending' if pending}") + else + handle_errors(@domain) + end end def delete diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index da64f3df8..32d23bc3b 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -1,26 +1,71 @@ module Actions - class DomainCreate - attr_reader :domain, :params + class DomainUpdate + attr_reader :domain, :params, :bypass_verify - def initialize(domain, params) + def initialize(domain, params, bypass_verify) @domain = domain @params = params + @bypass_verify = bypass_verify end def call + @changes_registrant = false + validate_domain_integrity - verify_registrant_change # Should be last step - assign_admin_contact_changes if params[:contacts] - assign_tech_contact_changes if params[:contacts] + assign_new_registrant + assign_nameserver_modifications + assign_admin_contact_changes + assign_tech_contact_changes + assign_requested_statuses + + commit end def validate_domain_integrity + domain.auth_info = params[:auth_info] if params[:auth_info] + return unless domain.discarded? domain.add_epp_error('2304', nil, nil, 'Object status prohibits operation') end + def assign_new_registrant + return unless params[:registrant] + + domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) unless params[:registrant][:code] + regt = Registrant.find_by(code: params[:registrant][:code]) + if regt.present? + return if domain.registrant == regt + + @changes_registrant = true if domain.registrant.ident != regt.ident + domain.registrant = regt + else + domain.add_epp_error('2303', 'registrant', params[:registrant_id], %i[registrant not_found]) + end + end + + def assign_nameserver_modifications + return unless params[:nameservers] + + nameservers = [] + params[:nameservers].select { |ns| ns[:action] == 'rem' }.each do |ns_attr| + ns = domain.nameservers.find_by_hash_params(ns_attr.except(:action)).first + domain.add_epp_error('2303', 'hostAttr', ns_attr[:hostname], %i[nameservers not_found]) and break unless ns + nameservers << { id: ns.id, _destroy: 1 } + end + + params[:nameservers].select { |ns| ns[:action] == 'add' }.each do |ns_attr| + nameservers << ns_attr.except(:action) + end + + return unless nameservers.present? + + domain.nameservers_attributes = nameservers + end + def assign_admin_contact_changes + return unless params[:contacts] + props = [] contacts = params[:contacts].select { |c| c[:type] == 'admin' } @@ -31,138 +76,112 @@ module Actions contacts.select { |c| c[:action] == 'rem' }.each do |c| dc = domain.admin_domain_contacts.find_by(contact_code_cache: c[:code]) - domain.add_epp_error('2303', 'contact', at[:contact_code_cache], [:domain_contacts, :not_found]) and break unless dc - - props << { id: dc.id, _destroy: 1 } + if dc.present? + props << { id: dc.id, _destroy: 1 } + else + domain.add_epp_error('2303', 'contact', c[:code], %i[domain_contacts not_found]) + end end contacts.select { |c| c[:action] == 'add' }.each do |c| contact = Epp::Contact.find_by_epp_code(c[:code]) - domain.add_epp_error('2303', 'contact', c[:code], [:domain_contacts, :not_found]) and break unless contact - domain.add_epp_error('2306', 'contact', c[:code], [:domain_contacts, :admin_contact_can_be_only_private_person]) and break if contact.org? - - props << { id: contact.id, code: contact.code } + if contact.present? + if contact.org? + domain.add_epp_error('2306', 'contact', c[:code], %i[domain_contacts admin_contact_can_be_only_private_person]) + else + props << { contact_id: contact.id, contact_code_cache: contact.code } + end + else + domain.add_epp_error('2303', 'contact', c[:code], %i[domain_contacts not_found]) + end end + return unless props.present? + domain.admin_domain_contacts_attributes = props end def assign_tech_contact_changes - props = [] - contacts = params[:contacts].select { |c| c[:type] == 'admin' } + return unless params[:contacts] - if contacts.present? && domain.admin_change_prohibited? - domain.add_epp_error('2304', 'admin', DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) + props = [] + contacts = params[:contacts].select { |c| c[:type] == 'tech' } + + if contacts.present? && domain.tech_change_prohibited? + domain.add_epp_error('2304', 'tech', DomainStatus::SERVER_TECH_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) return end contacts.select { |c| c[:action] == 'rem' }.each do |c| - dc = domain.admin_domain_contacts.find_by(contact_code_cache: c[:code]) - domain.add_epp_error('2303', 'contact', at[:contact_code_cache], [:domain_contacts, :not_found]) and break unless dc - - props << { id: dc.id, _destroy: 1 } + dc = domain.tech_domain_contacts.find_by(contact_code_cache: c[:code]) + if dc.present? + props << { id: dc.id, _destroy: 1 } + else + domain.add_epp_error('2303', 'contact', c[:code], %i[domain_contacts not_found]) + end end contacts.select { |c| c[:action] == 'add' }.each do |c| contact = Epp::Contact.find_by_epp_code(c[:code]) - domain.add_epp_error('2303', 'contact', c[:code], [:domain_contacts, :not_found]) and break unless contact - domain.add_epp_error('2306', 'contact', c[:code], [:domain_contacts, :admin_contact_can_be_only_private_person]) and break if contact.org? - - props << { id: contact.id, code: contact.code } + if contact.present? + props << { contact_id: contact.id, contact_code_cache: contact.code } + else + domain.add_epp_error('2303', 'contact', c[:code], %i[domain_contacts not_found]) + end end - domain.admin_domain_contacts_attributes = props + return unless props.present? + + domain.tech_domain_contacts_attributes = props end - def verify_registrant_change - return if !params[:registrant] || domain.registrant.code == params[:registrant][:code] + def assign_requested_statuses + return unless params[:statuses] - if domain.disputed? - domain.add_epp_error('2304', nil, nil, 'Required parameter missing; reservedpw element required for dispute domains') and return unless params[:reserved_pw] - dispute = Dispute.active.find_by(domain_name: name, password: params[:reserved_pw]) - domain.add_epp_error('2202', nil, nil, 'Invalid authorization information; invalid reserved>pw value') and return unless dispute - Dispute.close_by_domain(name) + rem = [] + add = [] + + invalid = false + params[:statuses].each do |s| + unless DomainStatus::CLIENT_STATUSES.include?(s[:status]) + domain.add_epp_error('2303', 'status', s[:status], %i[domain_statuses not_found]) + invalid = true + end end - return unless params[:registrant][:verified] && Setting.request_confirmation_on_registrant_change_enabled - - domain.registrant_verification_asked!(frame.to_s, current_user.id) - end - - def assign_registrant - domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) and return unless params[:registrant_id] - - regt = Registrant.find_by(code: params[:registrant_id]) - domain.add_epp_error('2303', 'registrant', params[:registrant_id], %i[registrant not_found]) and return unless regt - - domain.registrant = regt - end - - def assign_domain_attributes - domain.name = params[:name].strip.downcase - domain.registrar = Registrar.find(params[:registrar_id]) - domain.period = params[:period] - domain.period_unit = params[:period_unit] - domain.transfer_code = params[:transfer_code] if params[:transfer_code].present? - domain.reserved_pw = params[:reserved_pw] if params[:reserved_pw].present? - domain.dnskeys_attributes = params[:dnskeys_attributes] - end - - def assign_nameservers - domain.nameservers_attributes = params[:nameservers_attributes] - end - - def assign_admin_contacts - attrs = [] - params[:admin_domain_contacts_attributes].each do |c| - contact = Contact.find_by(code: c) - domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) unless contact.present? - attrs << { contact_id: contact.id, contact_code_cache: contact.code } if contact + params[:statuses].select { |s| s[:action] == 'rem' }.each do |s| + if domain.statuses.include?(s[:status]) + rem << s[:status] + else + domain.add_epp_error('2303', 'status', s[:status], %i[domain_statuses not_found]) + invalid = true + end end - domain.admin_domain_contacts_attributes = attrs + params[:statuses].select { |s| s[:action] == 'add' }.each { |s| add << s[:status] } + return if invalid + + domain.statuses = domain.statuses - rem + add end - def assign_tech_contacts - attrs = [] - params[:tech_domain_contacts_attributes].each do |c| - contact = Contact.find_by(code: c) - domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) unless contact.present? - attrs << { contact_id: contact.id, contact_code_cache: contact.code } if contact + def verify_registrant_change? + return false unless @changes_registrant + return false if params[:registrant][:verified] == true + return true unless domain.disputed? + + if params[:reserved_pw] + dispute = Dispute.active.find_by(domain_name: domain.name, password: params[:reserved_pw]) + if dispute + Dispute.close_by_domain(domain.name) + return false + else + domain.add_epp_error('2202', nil, nil, 'Invalid authorization information; invalid reserved>pw value') + end + else + domain.add_epp_error('2304', nil, nil, 'Required parameter missing; reservedpw element required for dispute domains') end - domain.tech_domain_contacts_attributes = attrs - end - - def assign_expiry_time - period = domain.period.to_i - plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym - expire_time = (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day - domain.expire_time = expire_time - end - - def debit_registrar - @domain_pricelist ||= domain.pricelist('create', domain.period.try(:to_i), domain.period_unit) - if @domain_pricelist.try(:price) && domain.registrar.balance < @domain_pricelist.price.amount - domain.add_epp_error(2104, nil, nil, I18n.t('billing_failure_credit_balance_low')) - return - elsif !@domain_pricelist.try(:price) - domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) - return - end - - domain.registrar.debit!({ sum: @domain_pricelist.price.amount, price: @domain_pricelist, - description: "#{I18n.t('create')} #{domain.name}", - activity_type: AccountActivity::CREATE }) - end - - def process_auction_and_disputes - dn = DNS::DomainName.new(SimpleIDN.to_unicode(params[:name])) - Dispute.close_by_domain(domain.name) - return unless Domain.release_to_auction && dn.pending_registration? - - auction = Auction.find_by(domain: domain.name, status: Auction.statuses[:payment_received]) - auction.domain_registered! + true end def maybe_attach_legal_doc @@ -178,16 +197,18 @@ module Actions end def commit - unless domain.valid? - domain.errors.delete(:name_dirty) if domain.errors[:puny_label].any? - return false if domain.errors.any? + return false if domain.errors[:epp_errors].any? + return false unless domain.valid? + + if verify_registrant_change? && Setting.request_confirmation_on_registrant_change_enabled + return if bypass_verify + + domain.registrant_verification_asked!(params.to_s, params[:registrar_id]) end - # @domain.add_legal_file_to_new(params[:parsed_frame]) - debit_registrar - return false if domain.errors.any? + return false if domain.errors[:epp_errors].any? + return false unless domain.valid? - process_auction_and_disputes domain.save end end diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 442b37102..5a30f9778 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -1,6 +1,7 @@ require 'deserializers/xml/legal_document' require 'deserializers/xml/nameserver' require 'deserializers/xml/domain_create' +require 'deserializers/xml/domain_update' class Epp::Domain < Domain include EppErrors @@ -116,6 +117,7 @@ class Epp::Domain < Domain def attrs_from(frame, current_user, action = nil) at = {}.with_indifferent_access + # KORRAS registrant_frame = frame.css('registrant').first code = registrant_frame.try(:text) if code.present? @@ -131,7 +133,7 @@ class Epp::Domain < Domain else add_epp_error('2306', nil, nil, [:registrant, :cannot_be_missing]) end if registrant_frame - + # KORRAS at[:name] = frame.css('name').text if new_record? # Done at[:registrar_id] = current_user.registrar.try(:id) # Done @@ -434,7 +436,7 @@ class Epp::Domain < Domain at[:tech_domain_contacts_attributes] += at_add[:tech_domain_contacts_attributes] at[:dnskeys_attributes] += at_add[:dnskeys_attributes] at[:statuses] = - statuses - domain_statuses_attrs(frame.css('rem'), 'rem') + domain_statuses_attrs(frame.css('add'), 'add') +statuses - domain_statuses_attrs(frame.css('rem'), 'rem') + domain_statuses_attrs(frame.css('add'), 'add') if errors.empty? && verify self.upid = current_user.registrar.id if current_user.registrar diff --git a/lib/deserializers/xml/domain_update.rb b/lib/deserializers/xml/domain_update.rb index f89eef8f2..15acf8b4b 100644 --- a/lib/deserializers/xml/domain_update.rb +++ b/lib/deserializers/xml/domain_update.rb @@ -14,7 +14,8 @@ module Deserializers def call obj = { domain: frame.css('name')&.text, registrant: registrant, contacts: contacts, - auth_info: if_present('pw'), nameservers: nameservers, dns_keys: dns_keys } + auth_info: if_present('authInfo > pw'), nameservers: nameservers, dns_keys: dns_keys, + registrar_id: registrar, statuses: statuses, reserved_pw: if_present('reserved > pw') } obj.reject { |_key, val| val.blank? } end @@ -41,14 +42,14 @@ module Deserializers def nameservers nameservers = [] frame.css('add > ns > hostAttr').each do |ns| - nsrv = { nameserver: ns.css('hostName').text, host_addr: [], action: 'add' } - ns.css('hostAddr').each { |ha| nsrv[:host_addr] << { proto: ha.attr('ip').to_s.downcase, addr: ha.text } } + nsrv = Deserializers::Xml::Nameserver.new(ns).call + nsrv[:action] = 'add' nameservers << nsrv end frame.css('rem > ns > hostAttr').each do |ns| - nsrv = { nameserver: ns.css('hostName').text, host_addr: [], action: 'rem' } - ns.css('hostAddr').each { |ha| nsrv[:host_addr] << { proto: ha.attr('ip').to_s.downcase, addr: ha.text } } + nsrv = Deserializers::Xml::Nameserver.new(ns).call + nsrv[:action] = 'rem' nameservers << nsrv end @@ -66,6 +67,17 @@ module Deserializers added + removed end + def statuses + return unless frame.css('status').present? + + statuses = [] + + frame.css('add > status').each { |entry| statuses << { status: entry.attr('s').to_s, action: 'add' } } + frame.css('rem > status').each { |entry| statuses << { status: entry.attr('s').to_s, action: 'rem' } } + + statuses + end + def if_present(css_path) return if frame.css(css_path).blank? From 33b8f031c7b2d9f25fc06386bf554012e7561c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 17 Dec 2020 14:45:11 +0200 Subject: [PATCH 09/80] Fix DNSSEC modifitcations in DomainUpdate --- app/models/actions/domain_update.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index 32d23bc3b..86454e727 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -17,6 +17,7 @@ module Actions assign_admin_contact_changes assign_tech_contact_changes assign_requested_statuses + assign_dnssec_modifications commit end @@ -63,6 +64,21 @@ module Actions domain.nameservers_attributes = nameservers end + def assign_dnssec_modifications + dnskeys = [] + params[:dns_keys].select { |dk| dk[:action] == 'rem' }.each do |key| + dnkey = domain.dnskeys.find_by(key.except(:action)) + domain.add_epp_error('2303', nil, nil, %i[dnskeys not_found]) unless dnkey + dnskeys << { id: dnkey.id, _destroy: 1 } if dnkey + end + + params[:dns_keys].select { |dk| dk[:action] == 'add' }.each do |key| + dnskeys << key.except(:action) + end + + domain.dnskeys_attributes = dnskeys + end + def assign_admin_contact_changes return unless params[:contacts] From b44ce9f75213d66d997f1061712b0f4b35fa51b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 17 Dec 2020 17:17:06 +0200 Subject: [PATCH 10/80] Port domain registrant confirmation post logic to DomainUpdate action --- app/models/actions/domain_update.rb | 15 +- app/models/epp/domain.rb | 289 +--------------------------- 2 files changed, 15 insertions(+), 289 deletions(-) diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index 86454e727..26fae80b0 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -65,6 +65,8 @@ module Actions end def assign_dnssec_modifications + return unless params[:dns_keys] + dnskeys = [] params[:dns_keys].select { |dk| dk[:action] == 'rem' }.each do |key| dnkey = domain.dnskeys.find_by(key.except(:action)) @@ -73,6 +75,13 @@ module Actions end params[:dns_keys].select { |dk| dk[:action] == 'add' }.each do |key| + if key[:pubKey] && !Setting.key_data_allowed + domain.add_epp_error('2306', nil, nil, %i[dnskeys key_data_not_allowed]) + end + if key[:digest] && !Setting.ds_data_allowed + domain.add_epp_error('2306', nil, nil, %i[dnskeys ds_data_not_allowed]) + end + dnskeys << key.except(:action) end @@ -216,10 +225,10 @@ module Actions return false if domain.errors[:epp_errors].any? return false unless domain.valid? - if verify_registrant_change? && Setting.request_confirmation_on_registrant_change_enabled - return if bypass_verify + if verify_registrant_change? && !bypass_verify && + Setting.request_confirmation_on_registrant_change_enabled && !bypass_verify - domain.registrant_verification_asked!(params.to_s, params[:registrar_id]) + domain.registrant_verification_asked!(params, params[:registrar_id]) end return false if domain.errors[:epp_errors].any? diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 5a30f9778..8675d8ba3 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -114,53 +114,6 @@ class Epp::Domain < Domain admin_contacts << registrant if admin_domain_contacts.blank? && !registrant.org? end - def attrs_from(frame, current_user, action = nil) - at = {}.with_indifferent_access - - # KORRAS - registrant_frame = frame.css('registrant').first - code = registrant_frame.try(:text) - if code.present? - if action == 'chg' && registrant_change_prohibited? - add_epp_error('2304', "status", DomainStatus::SERVER_REGISTRANT_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) - end - regt = Registrant.find_by(code: code) - if regt - at[:registrant_id] = regt.id - else - add_epp_error('2303', 'registrant', code, [:registrant, :not_found]) - end - else - add_epp_error('2306', nil, nil, [:registrant, :cannot_be_missing]) - end if registrant_frame - # KORRAS - - at[:name] = frame.css('name').text if new_record? # Done - at[:registrar_id] = current_user.registrar.try(:id) # Done - period = frame.css('period').text # Done - at[:period] = (period.to_i == 0) ? 1 : period.to_i # Done - at[:period_unit] = Epp::Domain.parse_period_unit_from_frame(frame) || 'y' # Done - at[:reserved_pw] = frame.css('reserved > pw').text # Done - pw = frame.css('authInfo > pw').text # Done - at[:transfer_code] = pw if pw.present? # Done - # at[:statuses] = domain_statuses_attrs(frame, action) - - at[:nameservers_attributes] = nameservers_attrs(frame, action) - at[:admin_domain_contacts_attributes] = admin_domain_contacts_attrs(frame, action) - at[:tech_domain_contacts_attributes] = tech_domain_contacts_attrs(frame, action) - - if new_record? - dnskey_frame = frame.css('extension create') - else - dnskey_frame = frame - end - - at[:dnskeys_attributes] = dnskeys_attrs(dnskey_frame, action) - - at - end - - # Adding legal doc to domain and # if something goes wrong - raise Rollback error def add_legal_file_to_new frame @@ -176,243 +129,6 @@ class Epp::Domain < Domain self.legal_document_id = doc.id end - def nameservers_attrs(frame, action) - ns_list = ::Deserializers::Xml::Nameservers.new(frame).call - - if action == 'rem' - to_destroy = [] - ns_list.each do |ns_attrs| - nameserver = nameservers.find_by_hash_params(ns_attrs).first - if nameserver.blank? - add_epp_error('2303', 'hostAttr', ns_attrs[:hostname], [:nameservers, :not_found]) - else - to_destroy << { - id: nameserver.id, - _destroy: 1 - } - end - end - - return to_destroy - else - return ns_list - end - end - - def admin_domain_contacts_attrs(frame, action) - admin_attrs = domain_contact_attrs_from(frame, action, 'admin') - - if admin_attrs.present? && admin_change_prohibited? - add_epp_error('2304', 'admin', DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) - return [] - end - - case action - when 'rem' - return destroy_attrs(admin_attrs, admin_domain_contacts) - else - return admin_attrs - end - end - - def tech_domain_contacts_attrs(frame, action) - tech_attrs = domain_contact_attrs_from(frame, action, 'tech') - - if tech_attrs.present? && tech_change_prohibited? - add_epp_error('2304', 'tech', DomainStatus::SERVER_TECH_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) - return [] - end - - case action - when 'rem' - return destroy_attrs(tech_attrs, tech_domain_contacts) - else - return tech_attrs - end - end - - def destroy_attrs(attrs, dcontacts) - destroy_attrs = [] - attrs.each do |at| - domain_contact_id = dcontacts.find_by(contact_id: at[:contact_id]).try(:id) - - unless domain_contact_id - add_epp_error('2303', 'contact', at[:contact_code_cache], [:domain_contacts, :not_found]) - next - end - - destroy_attrs << { - id: domain_contact_id, - _destroy: 1 - } - end - - destroy_attrs - end - - def domain_contact_attrs_from(frame, action, type) - attrs = [] - frame.css('contact').each do |x| - next if x['type'] != type - - c = Epp::Contact.find_by_epp_code(x.text) - unless c - add_epp_error('2303', 'contact', x.text, [:domain_contacts, :not_found]) - next - end - - if action != 'rem' - if x['type'] == 'admin' && c.org? - add_epp_error('2306', 'contact', x.text, [:domain_contacts, :admin_contact_can_be_only_private_person]) - next - end - end - - attrs << { - contact_id: c.id, - contact_code_cache: c.code - } - end - - attrs - end - - def dnskeys_attrs(frame, action) - keys = [] - return keys if frame.blank? - inf_data = DnsSecKeys.new(frame) - - if action == 'rem' && - frame.css('rem > all').first.try(:text) == 'true' - keys = inf_data.mark_destroy_all dnskeys - else - if Setting.key_data_allowed - errors.add(:base, :ds_data_not_allowed) if inf_data.ds_data.present? - keys = inf_data.key_data - end - if Setting.ds_data_allowed - errors.add(:base, :key_data_not_allowed) if inf_data.key_data.present? - keys = inf_data.ds_data - end - if action == 'rem' - keys = inf_data.mark_destroy(dnskeys) - add_epp_error('2303', nil, nil, [:dnskeys, :not_found]) if keys.include? nil - end - end - - errors.any? ? [] : keys - end - - class DnsSecKeys - def initialize(frame) - @key_data = [] - @ds_data = [] - # schema validation prevents both in the same parent node - if frame.css('dsData').present? - ds_data_from frame - else - frame.css('keyData').each do |key| - @key_data.append key_data_from(key) - end - end - end - - attr_reader :key_data - attr_reader :ds_data - - def mark_destroy_all(dns_keys) - # if transition support required mark_destroy dns_keys when has ds/key values otherwise ... - dns_keys.map { |inf_data| mark inf_data } - end - - def mark_destroy(dns_keys) - (ds_data.present? ? ds_filter(dns_keys) : kd_filter(dns_keys)).map do |inf_data| - inf_data.blank? ? nil : mark(inf_data) - end - end - - private - - KEY_INTERFACE = {flags: 'flags', protocol: 'protocol', alg: 'alg', public_key: 'pubKey' } - DS_INTERFACE = - { ds_key_tag: 'keyTag', - ds_alg: 'alg', - ds_digest_type: 'digestType', - ds_digest: 'digest' - } - - def xm_copy(frame, map) - result = {} - map.each do |key, elem| - result[key] = frame.css(elem).first.try(:text) - end - result - end - - def key_data_from(frame) - xm_copy frame, KEY_INTERFACE - end - - def ds_data_from(frame) - frame.css('dsData').each do |ds_data| - key = ds_data.css('keyData') - ds = xm_copy ds_data, DS_INTERFACE - ds.merge(key_data_from key) if key.present? - @ds_data << ds - end - end - - def ds_filter(dns_keys) - @ds_data.map do |ds| - dns_keys.find_by(ds.slice(*DS_INTERFACE.keys)) - end - end - - def kd_filter(dns_keys) - @key_data.map do |key| - dns_keys.find_by(key) - end - end - - def mark(inf_data) - { id: inf_data.id, _destroy: 1 } - end - end - - def domain_statuses_attrs(frame, action) - status_list = domain_status_list_from(frame) - if action == 'rem' - to_destroy = [] - status_list.each do |x| - if statuses.include?(x) - to_destroy << x - else - add_epp_error('2303', 'status', x, [:domain_statuses, :not_found]) - end - end - - return to_destroy - else - return status_list - end - end - - def domain_status_list_from(frame) - status_list = [] - - frame.css('status').each do |x| - unless DomainStatus::CLIENT_STATUSES.include?(x['s']) - add_epp_error('2303', 'status', x['s'], [:domain_statuses, :not_found]) - next - end - - status_list << x['s'] - end - - status_list - end - - def update(frame, current_user, verify = true) return super if frame.blank? @@ -481,13 +197,14 @@ statuses - domain_statuses_attrs(frame.css('rem'), 'rem') + domain_statuses_attr def apply_pending_update! preclean_pendings user = ApiUser.find(pending_json['current_user_id']) - frame = Nokogiri::XML(pending_json['frame']) + frame = pending_json['frame'].with_indifferent_access self.statuses.delete(DomainStatus::PENDING_UPDATE) self.upid = user.registrar.id if user.registrar self.up_date = Time.zone.now - return unless update(frame, user, false) + return unless Actions::DomainUpdate.new(self, frame, true).call + clean_pendings! save! From 1fca6d907b5fc70c18570899ea6fc2d9a9046597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 18 Dec 2020 11:12:09 +0200 Subject: [PATCH 11/80] Fix domain update confirm tests --- app/models/epp/domain.rb | 67 +-------------------- test/jobs/domain_update_confirm_job_test.rb | 9 ++- 2 files changed, 8 insertions(+), 68 deletions(-) diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 8675d8ba3..8ab53b300 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -129,75 +129,10 @@ class Epp::Domain < Domain self.legal_document_id = doc.id end - def update(frame, current_user, verify = true) - return super if frame.blank? - - if discarded? - add_epp_error('2304', nil, nil, 'Object status prohibits operation') - return - end - - 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')) - - if doc = attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call) - frame.css("legalDocument").first.content = doc.path if doc&.persisted? - self.legal_document_id = doc.id - end - - at_add = attrs_from(frame.css('add'), current_user, 'add') - at[:nameservers_attributes] += at_add[:nameservers_attributes] - at[:admin_domain_contacts_attributes] += at_add[:admin_domain_contacts_attributes] - at[:tech_domain_contacts_attributes] += at_add[:tech_domain_contacts_attributes] - at[:dnskeys_attributes] += at_add[:dnskeys_attributes] - at[:statuses] = -statuses - domain_statuses_attrs(frame.css('rem'), 'rem') + domain_statuses_attrs(frame.css('add'), 'add') - - if errors.empty? && verify - self.upid = current_user.registrar.id if current_user.registrar - self.up_date = Time.zone.now - end - - registrant_verification_needed = false - # registrant block may not be present, so we need this to rule out false positives - if frame.css('registrant').text.present? - registrant_verification_needed = (registrant.code != frame.css('registrant').text) - end - - if registrant_verification_needed && disputed? - disputed_pw = frame.css('reserved > pw').text - if disputed_pw.blank? - add_epp_error('2304', nil, nil, 'Required parameter missing; reserved' \ - 'pw element required for dispute domains') - else - dispute = Dispute.active.find_by(domain_name: name, password: disputed_pw) - if dispute - Dispute.close_by_domain(name) - registrant_verification_needed = false # Prevent asking current registrant confirmation - else - add_epp_error('2202', nil, nil, 'Invalid authorization information; '\ - 'invalid reserved>pw value') - end - end - end - - unverified_registrant_params = frame.css('registrant').present? && - frame.css('registrant').attr('verified').to_s.downcase != 'yes' - - if registrant_verification_needed && errors.empty? && verify && - Setting.request_confirmation_on_registrant_change_enabled && - unverified_registrant_params - registrant_verification_asked!(frame.to_s, current_user.id) unless disputed? - end - - errors.empty? && super(at) - end - def apply_pending_update! preclean_pendings user = ApiUser.find(pending_json['current_user_id']) - frame = pending_json['frame'].with_indifferent_access + frame = pending_json['frame'] ? pending_json['frame'].with_indifferent_access : {} self.statuses.delete(DomainStatus::PENDING_UPDATE) self.upid = user.registrar.id if user.registrar diff --git a/test/jobs/domain_update_confirm_job_test.rb b/test/jobs/domain_update_confirm_job_test.rb index 9cca81eb7..a452daf0e 100644 --- a/test/jobs/domain_update_confirm_job_test.rb +++ b/test/jobs/domain_update_confirm_job_test.rb @@ -1,4 +1,5 @@ require "test_helper" +require 'deserializers/xml/domain_update' class DomainUpdateConfirmJobTest < ActiveSupport::TestCase def setup @@ -40,7 +41,9 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase " \n #{@new_registrant.code}\n \n \n \n \n \n" \ " \n #{@legal_doc_path}\n \n" \ " \n 20alla-1594199756\n \n\n" - @domain.pending_json['frame'] = epp_xml + parsed_frame = Deserializers::Xml::DomainUpdate.new(Nokogiri::XML(epp_xml), @domain.registrar.id).call + + @domain.pending_json['frame'] = parsed_frame @domain.update(pending_json: @domain.pending_json) @domain.reload @@ -55,7 +58,9 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase " \n #{@new_registrant.code}\n \n \n \n \n \n" \ " \n #{@legal_doc_path}\n \n" \ " \n 20alla-1594199756\n \n\n" - @domain.pending_json['frame'] = epp_xml + parsed_frame = Deserializers::Xml::DomainUpdate.new(Nokogiri::XML(epp_xml), @domain.registrar.id).call + + @domain.pending_json['frame'] = parsed_frame @domain.update(pending_json: @domain.pending_json) DomainUpdateConfirmJob.enqueue(@domain.id, RegistrantVerification::REJECTED) From 7caa544c83c50a9421c42a39b40f38b04b61dea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 29 Dec 2020 13:16:45 +0200 Subject: [PATCH 12/80] Fix some CC issues --- app/controllers/epp/domains_controller.rb | 3 +- .../process_update_confirmed.rb | 3 -- app/models/actions/domain_create.rb | 10 +++--- app/models/actions/domain_update.rb | 35 ++++++++++++------- app/models/epp/domain.rb | 20 ----------- lib/deserializers/xml/dnssec.rb | 5 +-- lib/deserializers/xml/domain_update.rb | 25 ++++++++----- lib/deserializers/xml/nameserver.rb | 2 +- 8 files changed, 50 insertions(+), 53 deletions(-) diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index 3432f8953..9cded2f75 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -40,7 +40,8 @@ module Epp authorize!(:update, @domain, @password) registrar_id = current_user.registrar.id - update_params = ::Deserializers::Xml::DomainUpdate.new(params[:parsed_frame], registrar_id).call + update_params = ::Deserializers::Xml::DomainUpdate.new(params[:parsed_frame], + registrar_id).call action = Actions::DomainUpdate.new(@domain, update_params, false) if action.call pending = @domain.epp_pending_update.present? diff --git a/app/interactions/domains/update_confirm/process_update_confirmed.rb b/app/interactions/domains/update_confirm/process_update_confirmed.rb index cf7c82a7a..320f0071f 100644 --- a/app/interactions/domains/update_confirm/process_update_confirmed.rb +++ b/app/interactions/domains/update_confirm/process_update_confirmed.rb @@ -24,13 +24,10 @@ module Domains user = ApiUser.find(domain.pending_json['current_user_id']) frame = domain.pending_json['frame'] ? domain.pending_json['frame'].with_indifferent_access : {} - #self.statuses.delete(DomainStatus::PENDING_UPDATE) domain.upid = user.registrar.id if user.registrar domain.up_date = Time.zone.now Actions::DomainUpdate.new(domain, frame, true).call - - #save! end end end diff --git a/app/models/actions/domain_create.rb b/app/models/actions/domain_create.rb index 9cff3ce17..2d351e470 100644 --- a/app/models/actions/domain_create.rb +++ b/app/models/actions/domain_create.rb @@ -69,7 +69,7 @@ module Actions attrs = [] params[:admin_domain_contacts_attributes].each do |c| contact = Contact.find_by(code: c) - domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) unless contact.present? + domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) if contact.blank? attrs << { contact_id: contact.id, contact_code_cache: contact.code } if contact end @@ -80,7 +80,7 @@ module Actions attrs = [] params[:tech_domain_contacts_attributes].each do |c| contact = Contact.find_by(code: c) - domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) unless contact.present? + domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) if contact.blank? attrs << { contact_id: contact.id, contact_code_cache: contact.code } if contact end @@ -104,9 +104,9 @@ module Actions return end - domain.registrar.debit!({ sum: @domain_pricelist.price.amount, price: @domain_pricelist, - description: "#{I18n.t('create')} #{domain.name}", - activity_type: AccountActivity::CREATE }) + domain.registrar.debit!(sum: @domain_pricelist.price.amount, price: @domain_pricelist, + description: "#{I18n.t('create')} #{domain.name}", + activity_type: AccountActivity::CREATE) end def process_auction_and_disputes diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index 63a604335..0c06db6f2 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -33,7 +33,10 @@ module Actions def assign_new_registrant return unless params[:registrant] - domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) unless params[:registrant][:code] + unless params[:registrant][:code] + domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) + end + regt = Registrant.find_by(code: params[:registrant][:code]) if regt.present? return if domain.registrant == regt @@ -51,7 +54,10 @@ module Actions nameservers = [] params[:nameservers].select { |ns| ns[:action] == 'rem' }.each do |ns_attr| ns = domain.nameservers.find_by_hash_params(ns_attr.except(:action)).first - domain.add_epp_error('2303', 'hostAttr', ns_attr[:hostname], %i[nameservers not_found]) and break unless ns + unless ns + domain.add_epp_error('2303', 'hostAttr', ns_attr[:hostname], %i[nameservers not_found]) + break + end nameservers << { id: ns.id, _destroy: 1 } end @@ -59,7 +65,7 @@ module Actions nameservers << ns_attr.except(:action) end - return unless nameservers.present? + return if nameservers.blank? domain.nameservers_attributes = nameservers end @@ -95,7 +101,8 @@ module Actions contacts = params[:contacts].select { |c| c[:type] == 'admin' } if contacts.present? && domain.admin_change_prohibited? - domain.add_epp_error('2304', 'admin', DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) + domain.add_epp_error('2304', 'admin', DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED, + I18n.t(:object_status_prohibits_operation)) return end @@ -109,10 +116,11 @@ module Actions end contacts.select { |c| c[:action] == 'add' }.each do |c| - contact = Epp::Contact.find_by_epp_code(c[:code]) + contact = Epp::Contact.find_by(code: c[:code]) if contact.present? if contact.org? - domain.add_epp_error('2306', 'contact', c[:code], %i[domain_contacts admin_contact_can_be_only_private_person]) + domain.add_epp_error('2306', 'contact', c[:code], + %i[domain_contacts admin_contact_can_be_only_private_person]) else props << { contact_id: contact.id, contact_code_cache: contact.code } end @@ -121,7 +129,7 @@ module Actions end end - return unless props.present? + return if props.blank? domain.admin_domain_contacts_attributes = props end @@ -133,7 +141,8 @@ module Actions contacts = params[:contacts].select { |c| c[:type] == 'tech' } if contacts.present? && domain.tech_change_prohibited? - domain.add_epp_error('2304', 'tech', DomainStatus::SERVER_TECH_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) + domain.add_epp_error('2304', 'tech', DomainStatus::SERVER_TECH_CHANGE_PROHIBITED, + I18n.t(:object_status_prohibits_operation)) return end @@ -147,7 +156,7 @@ module Actions end contacts.select { |c| c[:action] == 'add' }.each do |c| - contact = Epp::Contact.find_by_epp_code(c[:code]) + contact = Epp::Contact.find_by(code: c[:code]) if contact.present? props << { contact_id: contact.id, contact_code_cache: contact.code } else @@ -155,7 +164,7 @@ module Actions end end - return unless props.present? + return if props.blank? domain.tech_domain_contacts_attributes = props end @@ -203,10 +212,12 @@ module Actions Dispute.close_by_domain(domain.name) return false else - domain.add_epp_error('2202', nil, nil, 'Invalid authorization information; invalid reserved>pw value') + domain.add_epp_error('2202', nil, nil, + 'Invalid authorization information; invalid reserved>pw value') end else - domain.add_epp_error('2304', nil, nil, 'Required parameter missing; reservedpw element required for dispute domains') + domain.add_epp_error('2304', nil, nil, "Required parameter missing; reservedpw element " \ + 'required for dispute domains') end true diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 8ab53b300..697787183 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -129,26 +129,6 @@ class Epp::Domain < Domain self.legal_document_id = doc.id end - def apply_pending_update! - preclean_pendings - user = ApiUser.find(pending_json['current_user_id']) - frame = pending_json['frame'] ? pending_json['frame'].with_indifferent_access : {} - - self.statuses.delete(DomainStatus::PENDING_UPDATE) - self.upid = user.registrar.id if user.registrar - self.up_date = Time.zone.now - - return unless Actions::DomainUpdate.new(self, frame, true).call - - clean_pendings! - - save! - - WhoisRecord.find_by(domain_id: id).save # need to reload model - - true - end - def apply_pending_delete! preclean_pendings statuses.delete(DomainStatus::PENDING_DELETE_CONFIRMATION) diff --git a/lib/deserializers/xml/dnssec.rb b/lib/deserializers/xml/dnssec.rb index f255716d4..a9c348ea6 100644 --- a/lib/deserializers/xml/dnssec.rb +++ b/lib/deserializers/xml/dnssec.rb @@ -3,9 +3,10 @@ module Deserializers class DnssecKey attr_reader :frame, :dsa - KEY_INTERFACE = { flags: 'flags', protocol: 'protocol', alg: 'alg', public_key: 'pubKey' } + KEY_INTERFACE = { flags: 'flags', protocol: 'protocol', alg: 'alg', + public_key: 'pubKey' }.freeze DS_INTERFACE = { ds_key_tag: 'keyTag', ds_alg: 'alg', ds_digest_type: 'digestType', - ds_digest: 'digest' } + ds_digest: 'digest' }.freeze def initialize(frame, dsa) @frame = frame diff --git a/lib/deserializers/xml/domain_update.rb b/lib/deserializers/xml/domain_update.rb index 15acf8b4b..4a6a5b74b 100644 --- a/lib/deserializers/xml/domain_update.rb +++ b/lib/deserializers/xml/domain_update.rb @@ -14,8 +14,9 @@ module Deserializers def call obj = { domain: frame.css('name')&.text, registrant: registrant, contacts: contacts, - auth_info: if_present('authInfo > pw'), nameservers: nameservers, dns_keys: dns_keys, - registrar_id: registrar, statuses: statuses, reserved_pw: if_present('reserved > pw') } + auth_info: if_present('authInfo > pw'), nameservers: nameservers, + registrar_id: registrar, statuses: statuses, dns_keys: dns_keys, + reserved_pw: if_present('reserved > pw') } obj.reject { |_key, val| val.blank? } end @@ -23,7 +24,8 @@ module Deserializers def registrant return if frame.css('chg > registrant').blank? - { code: frame.css('chg > registrant').text, verified: frame.css('chg > registrant').attr('verified').to_s.downcase == 'yes' } + { code: frame.css('chg > registrant').text, + verified: frame.css('chg > registrant').attr('verified').to_s.downcase == 'yes' } end def contacts @@ -36,7 +38,7 @@ module Deserializers contacts << { code: c.text, type: c['type'], action: 'rem' } end - contacts.present? ? contacts : nil + contacts.presence end def nameservers @@ -53,7 +55,7 @@ module Deserializers nameservers << nsrv end - nameservers.present? ? nameservers : nil + nameservers.presence end def dns_keys @@ -62,18 +64,23 @@ module Deserializers removed = ::Deserializers::Xml::DnssecKeys.new(frame.css('rem')).call removed.each { |k| k[:action] = 'rem' } - return unless (added + removed).present? + return if (added + removed).blank? added + removed end def statuses - return unless frame.css('status').present? + return if frame.css('status').blank? statuses = [] - frame.css('add > status').each { |entry| statuses << { status: entry.attr('s').to_s, action: 'add' } } - frame.css('rem > status').each { |entry| statuses << { status: entry.attr('s').to_s, action: 'rem' } } + frame.css('add > status').each do |e| + statuses << { status: e.attr('s').to_s, action: 'add' } + end + + frame.css('rem > status').each do |e| + statuses << { status: e.attr('s').to_s, action: 'rem' } + end statuses end diff --git a/lib/deserializers/xml/nameserver.rb b/lib/deserializers/xml/nameserver.rb index f43407d68..03b264718 100644 --- a/lib/deserializers/xml/nameserver.rb +++ b/lib/deserializers/xml/nameserver.rb @@ -11,7 +11,7 @@ module Deserializers { hostname: frame.css('hostName').text, ipv4: frame.css('hostAddr[ip="v4"]').map(&:text).compact, - ipv6: frame.css('hostAddr[ip="v6"]').map(&:text).compact + ipv6: frame.css('hostAddr[ip="v6"]').map(&:text).compact, } end end From 50bf708b6a98e4a6b0dc857d60e1b37c6ddb008a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 29 Dec 2020 15:21:03 +0200 Subject: [PATCH 13/80] Use central method for appending legaldocs to domains/contacts --- .../process_update_confirmed.rb | 3 +- app/models/actions/base_action.rb | 24 +++++++++++ app/models/actions/contact_create.rb | 10 +---- app/models/actions/contact_delete.rb | 10 +---- app/models/actions/contact_update.rb | 9 +---- app/models/actions/domain_create.rb | 40 +++++++++---------- app/models/actions/domain_update.rb | 12 +----- app/models/epp/domain.rb | 15 ------- lib/deserializers/xml/domain_create.rb | 5 +++ lib/deserializers/xml/domain_update.rb | 6 ++- 10 files changed, 61 insertions(+), 73 deletions(-) create mode 100644 app/models/actions/base_action.rb diff --git a/app/interactions/domains/update_confirm/process_update_confirmed.rb b/app/interactions/domains/update_confirm/process_update_confirmed.rb index 320f0071f..2e57cddd8 100644 --- a/app/interactions/domains/update_confirm/process_update_confirmed.rb +++ b/app/interactions/domains/update_confirm/process_update_confirmed.rb @@ -21,8 +21,9 @@ module Domains end def update_domain + frame_json = domain.pending_json['frame'] user = ApiUser.find(domain.pending_json['current_user_id']) - frame = domain.pending_json['frame'] ? domain.pending_json['frame'].with_indifferent_access : {} + frame = frame_json ? frame_json.with_indifferent_access : {} domain.upid = user.registrar.id if user.registrar domain.up_date = Time.zone.now diff --git a/app/models/actions/base_action.rb b/app/models/actions/base_action.rb new file mode 100644 index 000000000..f29526753 --- /dev/null +++ b/app/models/actions/base_action.rb @@ -0,0 +1,24 @@ +module Actions + class BaseAction + def self.maybe_attach_legal_doc(entity, legal_doc) + return unless legal_doc + return if legal_doc[:body].starts_with?(ENV['legal_documents_dir']) + + entity.legal_documents.create( + document_type: legal_doc[:type], + body: legal_doc[:body] + ) + end + + def self.attach_legal_doc_to_new(entity, legal_doc, domain: true) + return unless legal_doc + + doc = LegalDocument.create( + documentable_type: domain ? Domain : Contact, + document_type: legal_doc[:type], + body: legal_doc[:body] + ) + entity.legal_documents = [doc] + end + end +end diff --git a/app/models/actions/contact_create.rb b/app/models/actions/contact_create.rb index 22fabc7b9..9c700f858 100644 --- a/app/models/actions/contact_create.rb +++ b/app/models/actions/contact_create.rb @@ -59,15 +59,7 @@ module Actions end def maybe_attach_legal_doc - return unless legal_document - - doc = LegalDocument.create( - documentable_type: Contact, - document_type: legal_document[:type], body: legal_document[:body] - ) - - contact.legal_documents = [doc] - contact.legal_document_id = doc.id + Actions::BaseAction.attach_legal_doc_to_new(contact, legal_document, domain: false) end def commit diff --git a/app/models/actions/contact_delete.rb b/app/models/actions/contact_delete.rb index 59032d566..2923b7de0 100644 --- a/app/models/actions/contact_delete.rb +++ b/app/models/actions/contact_delete.rb @@ -23,15 +23,7 @@ module Actions end def maybe_attach_legal_doc - return unless legal_document - - document = contact.legal_documents.create( - document_type: legal_document[:type], - body: legal_document[:body] - ) - - contact.legal_document_id = document.id - contact.save + Actions::BaseAction.maybe_attach_legal_doc(contact, legal_document) end def commit diff --git a/app/models/actions/contact_update.rb b/app/models/actions/contact_update.rb index 7ca7b6b04..cba8fad51 100644 --- a/app/models/actions/contact_update.rb +++ b/app/models/actions/contact_update.rb @@ -42,14 +42,7 @@ module Actions end def maybe_attach_legal_doc - return unless legal_document - - document = contact.legal_documents.create( - document_type: legal_document[:type], - body: legal_document[:body] - ) - - contact.legal_document_id = document.id + Actions::BaseAction.maybe_attach_legal_doc(contact, legal_document) end def maybe_update_ident diff --git a/app/models/actions/domain_create.rb b/app/models/actions/domain_create.rb index 2d351e470..7362be088 100644 --- a/app/models/actions/domain_create.rb +++ b/app/models/actions/domain_create.rb @@ -18,6 +18,7 @@ module Actions assign_tech_contacts domain.attach_default_contacts assign_expiry_time + maybe_attach_legal_doc commit end @@ -30,25 +31,33 @@ module Actions if dn.at_auction? domain.add_epp_error('2306', nil, nil, 'Parameter value policy error: domain is at auction') elsif dn.awaiting_payment? - domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw element required for reserved domains') + domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw element' \ + ' required for reserved domains') elsif dn.pending_registration? if params[:reserved_pw].blank? - domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw element is required') + domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw ' \ + 'element is required') else unless dn.available_with_code?(params[:reserved_pw]) - domain.add_epp_error('2202', nil, nil, 'Invalid authorization information; invalid reserved>pw value') + domain.add_epp_error('2202', nil, nil, 'Invalid authorization information; invalid ' \ + 'reserved>pw value') end end end end def assign_registrant - domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) and return unless params[:registrant_id] + unless params[:registrant_id] + domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) + return + end regt = Registrant.find_by(code: params[:registrant_id]) - domain.add_epp_error('2303', 'registrant', params[:registrant_id], %i[registrant not_found]) and return unless regt - - domain.registrant = regt + if regt + domain.registrant = regt + else + domain.add_epp_error('2303', 'registrant', params[:registrant_id], %i[registrant not_found]) + end end def assign_domain_attributes @@ -90,8 +99,8 @@ module Actions def assign_expiry_time period = domain.period.to_i plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym - expire_time = (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day - domain.expire_time = expire_time + exp = (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day + domain.expire_time = exp end def debit_registrar @@ -119,15 +128,7 @@ module Actions end def maybe_attach_legal_doc - return unless legal_document - - doc = LegalDocument.create( - documentable_type: Contact, - document_type: legal_document[:type], body: legal_document[:body] - ) - - contact.legal_documents = [doc] - contact.legal_document_id = doc.id + Actions::BaseAction.attach_legal_doc_to_new(domain, params[:legal_document], domain: true) end def commit @@ -135,9 +136,8 @@ module Actions domain.errors.delete(:name_dirty) if domain.errors[:puny_label].any? return false if domain.errors.any? end - # @domain.add_legal_file_to_new(params[:parsed_frame]) - debit_registrar + debit_registrar return false if domain.errors.any? process_auction_and_disputes diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index 0c06db6f2..b2c5c514c 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -18,6 +18,7 @@ module Actions assign_tech_contact_changes assign_requested_statuses assign_dnssec_modifications + maybe_attach_legal_doc commit end @@ -189,7 +190,6 @@ module Actions if domain.statuses.include?(s[:status]) rem << s[:status] else - STDOUT << 'AAAAAH' domain.add_epp_error('2303', 'status', s[:status], %i[statuses not_found]) invalid = true end @@ -224,15 +224,7 @@ module Actions end def maybe_attach_legal_doc - return unless legal_document - - doc = LegalDocument.create( - documentable_type: Contact, - document_type: legal_document[:type], body: legal_document[:body] - ) - - contact.legal_documents = [doc] - contact.legal_document_id = doc.id + Actions::BaseAction.maybe_attach_legal_doc(domain, params[:legal_document]) end def commit diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 697787183..b9b9710e2 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -114,21 +114,6 @@ class Epp::Domain < Domain admin_contacts << registrant if admin_domain_contacts.blank? && !registrant.org? end - # Adding legal doc to domain and - # if something goes wrong - raise Rollback error - def add_legal_file_to_new frame - legal_document_data = ::Deserializers::Xml::LegalDocument.new(frame).call - return unless legal_document_data - return if legal_document_data[:body].starts_with?(ENV['legal_documents_dir']) - - doc = LegalDocument.create(documentable_type: Domain, document_type: legal_document_data[:type], - body: legal_document_data[:body]) - self.legal_documents = [doc] - - frame.css("legalDocument").first.content = doc.path if doc&.persisted? - self.legal_document_id = doc.id - end - def apply_pending_delete! preclean_pendings statuses.delete(DomainStatus::PENDING_DELETE_CONFIRMATION) diff --git a/lib/deserializers/xml/domain_create.rb b/lib/deserializers/xml/domain_create.rb index d1d621573..e251dad88 100644 --- a/lib/deserializers/xml/domain_create.rb +++ b/lib/deserializers/xml/domain_create.rb @@ -19,6 +19,7 @@ module Deserializers obj[:tech_domain_contacts_attributes] = tech_contacts obj[:nameservers_attributes] = nameservers obj[:dnskeys_attributes] = dns_keys + obj[:legal_document] = legal_document obj end @@ -42,6 +43,10 @@ module Deserializers def dns_keys @dns_keys ||= ::Deserializers::Xml::DnssecKeys.new(frame).key_data end + + def legal_document + @legal_document ||= ::Deserializers::Xml::LegalDocument.new(frame).call + end end end end diff --git a/lib/deserializers/xml/domain_update.rb b/lib/deserializers/xml/domain_update.rb index 4a6a5b74b..b48f1e4aa 100644 --- a/lib/deserializers/xml/domain_update.rb +++ b/lib/deserializers/xml/domain_update.rb @@ -16,7 +16,7 @@ module Deserializers obj = { domain: frame.css('name')&.text, registrant: registrant, contacts: contacts, auth_info: if_present('authInfo > pw'), nameservers: nameservers, registrar_id: registrar, statuses: statuses, dns_keys: dns_keys, - reserved_pw: if_present('reserved > pw') } + reserved_pw: if_present('reserved > pw'), legal_document: legal_document } obj.reject { |_key, val| val.blank? } end @@ -85,6 +85,10 @@ module Deserializers statuses end + def legal_document + @legal_document ||= ::Deserializers::Xml::LegalDocument.new(frame).call + end + def if_present(css_path) return if frame.css(css_path).blank? From c23075fa199dda1afc5318160c457679f694a504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 6 Jan 2021 12:14:37 +0200 Subject: [PATCH 14/80] Fix some CC issues --- Gemfile.lock | 3 +- .../process_update_confirmed.rb | 2 +- app/models/actions/domain_update.rb | 233 ++++++++---------- 3 files changed, 112 insertions(+), 126 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2a0bb55b1..78a075243 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -479,6 +479,7 @@ GEM PLATFORMS ruby + x86_64-linux DEPENDENCIES active_interaction (~> 3.8) @@ -541,4 +542,4 @@ DEPENDENCIES wkhtmltopdf-binary (~> 0.12.5.1) BUNDLED WITH - 2.1.4 + 2.2.2 diff --git a/app/interactions/domains/update_confirm/process_update_confirmed.rb b/app/interactions/domains/update_confirm/process_update_confirmed.rb index 2e57cddd8..9088ce71f 100644 --- a/app/interactions/domains/update_confirm/process_update_confirmed.rb +++ b/app/interactions/domains/update_confirm/process_update_confirmed.rb @@ -22,7 +22,7 @@ module Domains def update_domain frame_json = domain.pending_json['frame'] - user = ApiUser.find(domain.pending_json['current_user_id']) + user = ApiUser.find(domain.pending_json['current_user_id']) frame = frame_json ? frame_json.with_indifferent_access : {} domain.upid = user.registrar.id if user.registrar diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index b2c5c514c..0d05bb853 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -12,12 +12,12 @@ module Actions @changes_registrant = false validate_domain_integrity - assign_new_registrant - assign_nameserver_modifications - assign_admin_contact_changes - assign_tech_contact_changes - assign_requested_statuses - assign_dnssec_modifications + assign_new_registrant if params[:registrant] + assign_nameserver_modifications if params[:nameservers] + assign_admin_contact_changes if params[:contacts] + assign_tech_contact_changes if params[:contacts] + assign_requested_statuses if params[:statuses] + assign_dnssec_modifications if params[:dns_keys] maybe_attach_legal_doc commit @@ -32,173 +32,158 @@ module Actions end def assign_new_registrant - return unless params[:registrant] - unless params[:registrant][:code] domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) end regt = Registrant.find_by(code: params[:registrant][:code]) - if regt.present? - return if domain.registrant == regt - - @changes_registrant = true if domain.registrant.ident != regt.ident - domain.registrant = regt - else + unless regt domain.add_epp_error('2303', 'registrant', params[:registrant_id], %i[registrant not_found]) + return end + + replace_domain_registrant(regt) + end + + def replace_domain_registrant(new_registrant) + return if domain.registrant == new_registrant + + @changes_registrant = true if domain.registrant.ident != new_registrant.ident + domain.registrant = new_registrant end def assign_nameserver_modifications - return unless params[:nameservers] - - nameservers = [] - params[:nameservers].select { |ns| ns[:action] == 'rem' }.each do |ns_attr| - ns = domain.nameservers.find_by_hash_params(ns_attr.except(:action)).first - unless ns - domain.add_epp_error('2303', 'hostAttr', ns_attr[:hostname], %i[nameservers not_found]) - break + @nameservers = [] + params[:nameservers].each do |ns_attr| + case ns_attr[:action] + when 'rem' + validate_ns_integrity(ns_attr) + when 'add' + @nameservers << ns_attr.except(:action) end - nameservers << { id: ns.id, _destroy: 1 } end - params[:nameservers].select { |ns| ns[:action] == 'add' }.each do |ns_attr| - nameservers << ns_attr.except(:action) + domain.nameservers_attributes = @nameservers if @nameservers.present? + end + + def validate_ns_integrity(ns_attr) + ns = domain.nameservers.find_by_hash_params(ns_attr.except(:action)).first + if ns + @nameservers << { id: ns.id, _destroy: 1 } + else + domain.add_epp_error('2303', 'hostAttr', ns_attr[:hostname], %i[nameservers not_found]) end - - return if nameservers.blank? - - domain.nameservers_attributes = nameservers end def assign_dnssec_modifications - return unless params[:dns_keys] + @dnskeys = [] - dnskeys = [] - params[:dns_keys].select { |dk| dk[:action] == 'rem' }.each do |key| - dnkey = domain.dnskeys.find_by(key.except(:action)) - domain.add_epp_error('2303', nil, nil, %i[dnskeys not_found]) unless dnkey - dnskeys << { id: dnkey.id, _destroy: 1 } if dnkey - end - - params[:dns_keys].select { |dk| dk[:action] == 'add' }.each do |key| - if key[:pubKey] && !Setting.key_data_allowed - domain.add_epp_error('2306', nil, nil, %i[dnskeys key_data_not_allowed]) + params[:dns_key].each do |key| + case key[:action] + when 'add' + validate_dnskey_integrity(key) && dnskeys << key.except(:action) + when 'rem' + assign_removable_dnskey(key) end - if key[:digest] && !Setting.ds_data_allowed - domain.add_epp_error('2306', nil, nil, %i[dnskeys ds_data_not_allowed]) - end - - dnskeys << key.except(:action) end domain.dnskeys_attributes = dnskeys end + def validate_dnskey_integrity(key) + if key[:pubKey] && !Setting.key_data_allowed + domain.add_epp_error('2306', nil, nil, %i[dnskeys key_data_not_allowed]) + elsif key[:digest] && !Setting.ds_data_allowed + domain.add_epp_error('2306', nil, nil, %i[dnskeys ds_data_not_allowed]) + end + + dnskeys << key.except(:action) + end + + def assign_removable_dnskey(key) + dnkey = domain.dnskeys.find_by(key.except(:action)) + domain.add_epp_error('2303', nil, nil, %i[dnskeys not_found]) unless dnkey + + @dnskeys << { id: dnkey.id, _destroy: 1 } if dnkey + end + def assign_admin_contact_changes - return unless params[:contacts] + props = gather_domain_contacts(params[:contacts].select { |c| c[:type] == 'admin' }) - props = [] - contacts = params[:contacts].select { |c| c[:type] == 'admin' } - - if contacts.present? && domain.admin_change_prohibited? + if props.any? && domain.admin_change_prohibited? domain.add_epp_error('2304', 'admin', DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) - return + elsif props.present? + domain.admin_domain_contacts_attributes = props end - - contacts.select { |c| c[:action] == 'rem' }.each do |c| - dc = domain.admin_domain_contacts.find_by(contact_code_cache: c[:code]) - if dc.present? - props << { id: dc.id, _destroy: 1 } - else - domain.add_epp_error('2303', 'contact', c[:code], %i[domain_contacts not_found]) - end - end - - contacts.select { |c| c[:action] == 'add' }.each do |c| - contact = Epp::Contact.find_by(code: c[:code]) - if contact.present? - if contact.org? - domain.add_epp_error('2306', 'contact', c[:code], - %i[domain_contacts admin_contact_can_be_only_private_person]) - else - props << { contact_id: contact.id, contact_code_cache: contact.code } - end - else - domain.add_epp_error('2303', 'contact', c[:code], %i[domain_contacts not_found]) - end - end - - return if props.blank? - - domain.admin_domain_contacts_attributes = props end def assign_tech_contact_changes - return unless params[:contacts] + props = gather_domain_contacts(params[:contacts].select { |c| c[:type] == 'tech' }, + admin: false) - props = [] - contacts = params[:contacts].select { |c| c[:type] == 'tech' } - - if contacts.present? && domain.tech_change_prohibited? + if props.any? && domain.tech_change_prohibited? domain.add_epp_error('2304', 'tech', DomainStatus::SERVER_TECH_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) - return + elsif props.present? + domain.tech_domain_contacts_attributes = props + end + end + + def gather_domain_contacts(contacts, admin: true) + props = [] + + contacts.each do |c| + contact = contact_for_action(action: c[:action], method: admin ? 'admin' : 'tech', + code: c[:code]) + entry = assign_contact(contact, add: c[:action] == 'add', admin: admin) + props << entry if entry.is_a?(Hash) end - contacts.select { |c| c[:action] == 'rem' }.each do |c| - dc = domain.tech_domain_contacts.find_by(contact_code_cache: c[:code]) - if dc.present? - props << { id: dc.id, _destroy: 1 } - else - domain.add_epp_error('2303', 'contact', c[:code], %i[domain_contacts not_found]) - end + props + end + + def contact_for_action(action:, method:, code:) + return Epp::Contact.find_by(code: code) if action == 'add' + return domain.admin_domain_contacts.find_by(contact_code_cache: code) if method == 'admin' + + domain.tech_domain_contacts.find_by(contact_code_cache: code) + end + + def assign_contact(obj, add: false, admin: true) + if obj.blank? + domain.add_epp_error('2303', 'contact', obj[:code], %i[domain_contacts not_found]) + elsif obj.org? && admin + domain.add_epp_error('2306', 'contact', obj[:code], + %i[domain_contacts admin_contact_can_be_only_private_person]) + else + add ? { contact_id: obj.id, contact_code_cache: obj.code } : { id: obj.id, _destroy: 1 } end - - contacts.select { |c| c[:action] == 'add' }.each do |c| - contact = Epp::Contact.find_by(code: c[:code]) - if contact.present? - props << { contact_id: contact.id, contact_code_cache: contact.code } - else - domain.add_epp_error('2303', 'contact', c[:code], %i[domain_contacts not_found]) - end - end - - return if props.blank? - - domain.tech_domain_contacts_attributes = props end def assign_requested_statuses - return unless params[:statuses] - rem = [] add = [] - invalid = false params[:statuses].each do |s| - unless DomainStatus::CLIENT_STATUSES.include?(s[:status]) - domain.add_epp_error('2303', 'status', s[:status], %i[statuses not_found]) - invalid = true + status, action = s.slice(:status, :action) + if permitted_status?(status, action) + action == 'add' ? add << status : rem << action end end - return if invalid + domain.statuses = domain.statuses - rem + add unless domain.errors.any? + end - params[:statuses].select { |s| s[:action] == 'rem' }.each do |s| - if domain.statuses.include?(s[:status]) - rem << s[:status] - else - domain.add_epp_error('2303', 'status', s[:status], %i[statuses not_found]) - invalid = true - end + def permitted_status?(status, action) + if DomainStatus::CLIENT_STATUSES.include?(status) && + (domain.statuses.include?(status) || action == 'add') + + true + else + domain.add_epp_error('2303', 'status', s[:status], %i[statuses not_found]) + false end - - params[:statuses].select { |s| s[:action] == 'add' }.each { |s| add << s[:status] } - return if invalid - - domain.statuses = domain.statuses - rem + add end def verify_registrant_change? @@ -216,7 +201,7 @@ module Actions 'Invalid authorization information; invalid reserved>pw value') end else - domain.add_epp_error('2304', nil, nil, "Required parameter missing; reservedpw element " \ + domain.add_epp_error('2304', nil, nil, 'Required parameter missing; reservedpw element ' \ 'required for dispute domains') end From c58b4fb2e913a8ab1f320310b5eb006b70e3cbe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 7 Jan 2021 13:59:12 +0200 Subject: [PATCH 15/80] Hash: select entries by keys --- .codeclimate.yml | 3 + app/controllers/repp/v1/domains_controller.rb | 5 + .../process_update_confirmed.rb | 10 +- app/models/actions/domain_create.rb | 126 +++++++++++------- app/models/actions/domain_update.rb | 118 ++++++++-------- app/models/nameserver.rb | 2 +- config/initializers/monkey_patches.rb | 1 + lib/core_monkey_patches/hash.rb | 5 + lib/deserializers/xml/dnssec.rb | 21 +-- lib/deserializers/xml/domain.rb | 16 ++- lib/deserializers/xml/domain_update.rb | 35 ++--- 11 files changed, 201 insertions(+), 141 deletions(-) create mode 100644 lib/core_monkey_patches/hash.rb diff --git a/.codeclimate.yml b/.codeclimate.yml index d079d891f..1b9e4ee26 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -30,6 +30,9 @@ checks: method-lines: config: threshold: 40 + method-count: + config: + threshold: 25 exclude_patterns: - "app/models/version/" - "bin/" diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index f69f33dd1..283d2bf7b 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -81,6 +81,11 @@ module Repp h = {} h[transfer_info_params[:id].match?(/\A[0-9]+\z/) ? :id : :name] = transfer_info_params[:id] @domain = Domain.find_by!(h) + + validate_registrar_authorization + end + + def validate_registrar_authorization return if @domain.registrar == current_user.registrar return if @domain.transfer_code.eql?(request.headers['Auth-Code']) diff --git a/app/interactions/domains/update_confirm/process_update_confirmed.rb b/app/interactions/domains/update_confirm/process_update_confirmed.rb index 9088ce71f..291253651 100644 --- a/app/interactions/domains/update_confirm/process_update_confirmed.rb +++ b/app/interactions/domains/update_confirm/process_update_confirmed.rb @@ -22,13 +22,17 @@ module Domains def update_domain frame_json = domain.pending_json['frame'] - user = ApiUser.find(domain.pending_json['current_user_id']) frame = frame_json ? frame_json.with_indifferent_access : {} + assign_domain_update_meta + + Actions::DomainUpdate.new(domain, frame, true).call + end + + def assign_domain_update_meta + user = ApiUser.find(domain.pending_json['current_user_id']) domain.upid = user.registrar.id if user.registrar domain.up_date = Time.zone.now - - Actions::DomainUpdate.new(domain, frame, true).call end end end diff --git a/app/models/actions/domain_create.rb b/app/models/actions/domain_create.rb index 7362be088..ced9c2327 100644 --- a/app/models/actions/domain_create.rb +++ b/app/models/actions/domain_create.rb @@ -1,5 +1,5 @@ module Actions - class DomainCreate + class DomainCreate # rubocop:disable Metrics/ClassLength attr_reader :domain, :params def initialize(domain, params) @@ -14,8 +14,7 @@ module Actions assign_registrant assign_nameservers - assign_admin_contacts - assign_tech_contacts + assign_domain_contacts domain.attach_default_contacts assign_expiry_time maybe_attach_legal_doc @@ -27,21 +26,25 @@ module Actions def validate_domain_integrity return unless Domain.release_to_auction - dn = DNS::DomainName.new(SimpleIDN.to_unicode(params[:name].strip.downcase)) + dn = DNS::DomainName.new(domain.name) if dn.at_auction? domain.add_epp_error('2306', nil, nil, 'Parameter value policy error: domain is at auction') elsif dn.awaiting_payment? domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw element' \ ' required for reserved domains') elsif dn.pending_registration? - if params[:reserved_pw].blank? - domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw ' \ - 'element is required') - else - unless dn.available_with_code?(params[:reserved_pw]) - domain.add_epp_error('2202', nil, nil, 'Invalid authorization information; invalid ' \ - 'reserved>pw value') - end + validate_reserved_password(dn) + end + end + + def validate_reserved_password(domain_name) + if params[:reserved_pw].blank? + domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw ' \ + 'element is required') + else + unless domain_name.available_with_code?(params[:reserved_pw]) + domain.add_epp_error('2202', nil, nil, 'Invalid authorization information; invalid ' \ + 'reserved>pw value') end end end @@ -63,79 +66,95 @@ module Actions def assign_domain_attributes domain.name = params[:name].strip.downcase domain.registrar = Registrar.find(params[:registrar_id]) - domain.period = params[:period] - domain.period_unit = params[:period_unit] + assign_domain_period + assign_domain_auth_codes + domain.dnskeys_attributes = params[:dnskeys_attributes] + end + + def assign_domain_auth_codes domain.transfer_code = params[:transfer_code] if params[:transfer_code].present? domain.reserved_pw = params[:reserved_pw] if params[:reserved_pw].present? - domain.dnskeys_attributes = params[:dnskeys_attributes] + end + + def assign_domain_period + domain.period = params[:period] + domain.period_unit = params[:period_unit] end def assign_nameservers domain.nameservers_attributes = params[:nameservers_attributes] end - def assign_admin_contacts - attrs = [] - params[:admin_domain_contacts_attributes].each do |c| - contact = Contact.find_by(code: c) - domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) if contact.blank? - attrs << { contact_id: contact.id, contact_code_cache: contact.code } if contact + def assign_contact(contact_code, admin: true) + contact = Contact.find_by(code: contact_code) + arr = admin ? @admin_contacts : @tech_contacts + if contact + arr << { contact_id: contact.id, contact_code_cache: contact.code } + else + domain.add_epp_error('2303', 'contact', contact_code, %i[domain_contacts not_found]) end - - domain.admin_domain_contacts_attributes = attrs end - def assign_tech_contacts - attrs = [] - params[:tech_domain_contacts_attributes].each do |c| - contact = Contact.find_by(code: c) - domain.add_epp_error('2303', 'contact', c, %i[domain_contacts not_found]) if contact.blank? - attrs << { contact_id: contact.id, contact_code_cache: contact.code } if contact - end + def assign_domain_contacts + @admin_contacts = [] + @tech_contacts = [] + params[:admin_domain_contacts_attributes].each { |c| assign_contact(c) } + params[:tech_domain_contacts_attributes].each { |c| assign_contact(c, admin: false) } - domain.tech_domain_contacts_attributes = attrs + domain.admin_domain_contacts_attributes = @admin_contacts + domain.tech_domain_contacts_attributes = @tech_contacts end def assign_expiry_time - period = domain.period.to_i + period = Integer(domain.period) plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym exp = (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day domain.expire_time = exp end - def debit_registrar - @domain_pricelist ||= domain.pricelist('create', domain.period.try(:to_i), domain.period_unit) - if @domain_pricelist.try(:price) && domain.registrar.balance < @domain_pricelist.price.amount - domain.add_epp_error(2104, nil, nil, I18n.t('billing_failure_credit_balance_low')) - return - elsif !@domain_pricelist.try(:price) + def action_billable? + unless domain_pricelist&.price domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) - return + return false end - domain.registrar.debit!(sum: @domain_pricelist.price.amount, price: @domain_pricelist, + if domain.registrar.balance < domain_pricelist.price.amount + domain.add_epp_error(2104, nil, nil, I18n.t('billing_failure_credit_balance_low')) + return false + end + + true + end + + def debit_registrar + return unless action_billable? + + domain.registrar.debit!(sum: domain_pricelist.price.amount, price: domain_pricelist, description: "#{I18n.t('create')} #{domain.name}", activity_type: AccountActivity::CREATE) end - def process_auction_and_disputes - dn = DNS::DomainName.new(SimpleIDN.to_unicode(params[:name])) - Dispute.close_by_domain(domain.name) - return unless Domain.release_to_auction && dn.pending_registration? + def domain_pricelist + @domain_pricelist ||= domain.pricelist('create', domain.period.try(:to_i), domain.period_unit) - auction = Auction.find_by(domain: domain.name, status: Auction.statuses[:payment_received]) - auction.domain_registered! + @domain_pricelist end def maybe_attach_legal_doc Actions::BaseAction.attach_legal_doc_to_new(domain, params[:legal_document], domain: true) end + def process_auction_and_disputes + dn = DNS::DomainName.new(domain.name) + Dispute.close_by_domain(domain.name) + return unless Domain.release_to_auction && dn.pending_registration? + + Auction.find_by(domain: domain.name, + status: Auction.statuses[:payment_received])&.domain_registered! + end + def commit - unless domain.valid? - domain.errors.delete(:name_dirty) if domain.errors[:puny_label].any? - return false if domain.errors.any? - end + return false if validation_process_errored? debit_registrar return false if domain.errors.any? @@ -143,5 +162,12 @@ module Actions process_auction_and_disputes domain.save end + + def validation_process_errored? + return if domain.valid? + + domain.errors.delete(:name_dirty) if domain.errors[:puny_label].any? + domain.errors.any? + end end end diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index 0d05bb853..176a9831b 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -1,28 +1,30 @@ module Actions - class DomainUpdate + class DomainUpdate # rubocop:disable Metrics/ClassLength attr_reader :domain, :params, :bypass_verify def initialize(domain, params, bypass_verify) @domain = domain @params = params @bypass_verify = bypass_verify + @changes_registrant = false end def call - @changes_registrant = false - validate_domain_integrity assign_new_registrant if params[:registrant] - assign_nameserver_modifications if params[:nameservers] - assign_admin_contact_changes if params[:contacts] - assign_tech_contact_changes if params[:contacts] - assign_requested_statuses if params[:statuses] - assign_dnssec_modifications if params[:dns_keys] + assign_relational_modifications + assign_requested_statuses maybe_attach_legal_doc commit end + def assign_relational_modifications + assign_nameserver_modifications if params[:nameservers] + assign_dnssec_modifications if params[:dns_keys] + (assign_admin_contact_changes && assign_tech_contact_changes) if params[:contacts] + end + def validate_domain_integrity domain.auth_info = params[:auth_info] if params[:auth_info] @@ -67,7 +69,7 @@ module Actions end def validate_ns_integrity(ns_attr) - ns = domain.nameservers.find_by_hash_params(ns_attr.except(:action)).first + ns = domain.nameservers.from_hash_params(ns_attr.except(:action)).first if ns @nameservers << { id: ns.id, _destroy: 1 } else @@ -78,16 +80,16 @@ module Actions def assign_dnssec_modifications @dnskeys = [] - params[:dns_key].each do |key| + params[:dns_keys].each do |key| case key[:action] when 'add' - validate_dnskey_integrity(key) && dnskeys << key.except(:action) + validate_dnskey_integrity(key) && @dnskeys << key.except(:action) when 'rem' assign_removable_dnskey(key) end end - domain.dnskeys_attributes = dnskeys + domain.dnskeys_attributes = @dnskeys end def validate_dnskey_integrity(key) @@ -136,7 +138,7 @@ module Actions contacts.each do |c| contact = contact_for_action(action: c[:action], method: admin ? 'admin' : 'tech', code: c[:code]) - entry = assign_contact(contact, add: c[:action] == 'add', admin: admin) + entry = assign_contact(contact, add: c[:action] == 'add', admin: admin, code: c[:code]) props << entry if entry.is_a?(Hash) end @@ -150,11 +152,11 @@ module Actions domain.tech_domain_contacts.find_by(contact_code_cache: code) end - def assign_contact(obj, add: false, admin: true) + def assign_contact(obj, add: false, admin: true, code:) if obj.blank? - domain.add_epp_error('2303', 'contact', obj[:code], %i[domain_contacts not_found]) + domain.add_epp_error('2303', 'contact', code, %i[domain_contacts not_found]) elsif obj.org? && admin - domain.add_epp_error('2306', 'contact', obj[:code], + domain.add_epp_error('2306', 'contact', code, %i[domain_contacts admin_contact_can_be_only_private_person]) else add ? { contact_id: obj.id, contact_code_cache: obj.code } : { id: obj.id, _destroy: 1 } @@ -162,70 +164,82 @@ module Actions end def assign_requested_statuses - rem = [] - add = [] + return unless params[:statuses] - params[:statuses].each do |s| - status, action = s.slice(:status, :action) - if permitted_status?(status, action) - action == 'add' ? add << status : rem << action - end - end + @rem = [] + @add = [] + @failed = false - domain.statuses = domain.statuses - rem + add unless domain.errors.any? + params[:statuses].each { |s| verify_status_eligiblity(s) } + domain.statuses = (domain.statuses - @rem + @add) unless @failed + end + + def verify_status_eligiblity(status_entry) + status, action = status_entry.select_keys(:status, :action) + return unless permitted_status?(status, action) + + action == 'add' ? @add << status : @rem << status end def permitted_status?(status, action) if DomainStatus::CLIENT_STATUSES.include?(status) && (domain.statuses.include?(status) || action == 'add') - - true - else - domain.add_epp_error('2303', 'status', s[:status], %i[statuses not_found]) - false + return true end + + domain.add_epp_error('2303', 'status', status, %i[statuses not_found]) + @failed = true + false end def verify_registrant_change? - return false unless @changes_registrant - return false if params[:registrant][:verified] == true + return if !@changes_registrant || params[:registrant][:verified] == true return true unless domain.disputed? + return validate_dispute_case if params[:reserved_pw] - if params[:reserved_pw] - dispute = Dispute.active.find_by(domain_name: domain.name, password: params[:reserved_pw]) - if dispute - Dispute.close_by_domain(domain.name) - return false - else - domain.add_epp_error('2202', nil, nil, - 'Invalid authorization information; invalid reserved>pw value') - end - else - domain.add_epp_error('2304', nil, nil, 'Required parameter missing; reservedpw element ' \ - 'required for dispute domains') - end + domain.add_epp_error('2304', nil, nil, 'Required parameter missing; reservedpw element ' \ + 'required for dispute domains') true end + def validate_dispute_case + dispute = Dispute.active.find_by(domain_name: domain.name, password: params[:reserved_pw]) + if dispute + Dispute.close_by_domain(domain.name) + false + else + domain.add_epp_error('2202', nil, nil, + 'Invalid authorization information; invalid reserved>pw value') + true + end + end + def maybe_attach_legal_doc Actions::BaseAction.maybe_attach_legal_doc(domain, params[:legal_document]) end - def commit - return false if domain.errors[:epp_errors].any? - return false unless domain.valid? - + def ask_registrant_verification if verify_registrant_change? && !bypass_verify && - Setting.request_confirmation_on_registrant_change_enabled && !bypass_verify + Setting.request_confirmation_on_registrant_change_enabled domain.registrant_verification_asked!(params, params[:registrar_id]) end + end - return false if domain.errors[:epp_errors].any? - return false unless domain.valid? + def commit + return false if any_errors? + + ask_registrant_verification + return false if any_errors? domain.save end + + def any_errors? + return true if domain.errors[:epp_errors].any? || domain.invalid? + + false + end end end diff --git a/app/models/nameserver.rb b/app/models/nameserver.rb index 3e4051165..85e64ce41 100644 --- a/app/models/nameserver.rb +++ b/app/models/nameserver.rb @@ -63,7 +63,7 @@ class Nameserver < ApplicationRecord end class << self - def find_by_hash_params params + def from_hash_params params params = params.with_indifferent_access rel = all rel = rel.where(hostname: params[:hostname]) diff --git a/config/initializers/monkey_patches.rb b/config/initializers/monkey_patches.rb index d342fb6b0..80109ecdd 100644 --- a/config/initializers/monkey_patches.rb +++ b/config/initializers/monkey_patches.rb @@ -1,4 +1,5 @@ require 'core_monkey_patches/array' +require 'core_monkey_patches/hash' require 'gem_monkey_patches/builder' require 'gem_monkey_patches/i18n' require 'gem_monkey_patches/paper_trail' diff --git a/lib/core_monkey_patches/hash.rb b/lib/core_monkey_patches/hash.rb new file mode 100644 index 000000000..debd1da7f --- /dev/null +++ b/lib/core_monkey_patches/hash.rb @@ -0,0 +1,5 @@ +class Hash + def select_keys(*args) + select { |k, _| args.include?(k) }.map { |_k, v| v } + end +end diff --git a/lib/deserializers/xml/dnssec.rb b/lib/deserializers/xml/dnssec.rb index a9c348ea6..89e7934a8 100644 --- a/lib/deserializers/xml/dnssec.rb +++ b/lib/deserializers/xml/dnssec.rb @@ -47,14 +47,16 @@ module Deserializers # schema validation prevents both in the same parent node if frame.css('dsData').present? - frame.css('dsData').each do |ds_data| - @ds_data << Deserializers::Xml::DnssecKey.new(ds_data, true).call - end - else - frame.css('keyData').each do |key| - @key_data << Deserializers::Xml::DnssecKey.new(key, false).call - end + frame.css('dsData').each { |k| @ds_data << key_from_params(k, dsa: true) } end + + return if frame.css('keyData').blank? + + frame.css('keyData').each { |k| @key_data << key_from_params(k, dsa: false) } + end + + def key_from_params(obj, dsa: false) + Deserializers::Xml::DnssecKey.new(obj, dsa).call end def call @@ -67,9 +69,8 @@ module Deserializers end def mark_destroy(dns_keys) - (ds_data.present? ? ds_filter(dns_keys) : kd_filter(dns_keys)).map do |inf_data| - inf_data.blank? ? nil : mark(inf_data) - end + data = ds_data.present? ? ds_filter(dns_keys) : kd_filter(dns_keys) + data.each { |inf_data| inf_data.blank? ? nil : mark(inf_data) } end private diff --git a/lib/deserializers/xml/domain.rb b/lib/deserializers/xml/domain.rb index 7b8ba3097..c663d4e7e 100644 --- a/lib/deserializers/xml/domain.rb +++ b/lib/deserializers/xml/domain.rb @@ -1,8 +1,7 @@ module Deserializers module Xml class Domain - attr_reader :frame - attr_reader :registrar + attr_reader :frame, :registrar def initialize(frame, registrar) @frame = frame @@ -15,15 +14,24 @@ module Deserializers registrar_id: registrar, registrant_id: if_present('registrant'), reserved_pw: if_present('reserved > pw'), - period: frame.css('period').text.present? ? Integer(frame.css('period').text) : 1, - period_unit: frame.css('period').first ? frame.css('period').first[:unit] : 'y', } + attributes.merge!(assign_period_attributes) + pw = frame.css('authInfo > pw').text attributes[:transfer_code] = pw if pw.present? attributes.compact end + def assign_period_attributes + period = frame.css('period') + + { + period: period.text.present? ? Integer(period.text) : 1, + period_unit: period.first ? period.first[:unit] : 'y', + } + end + def if_present(css_path) return if frame.css(css_path).blank? diff --git a/lib/deserializers/xml/domain_update.rb b/lib/deserializers/xml/domain_update.rb index b48f1e4aa..62b528bd7 100644 --- a/lib/deserializers/xml/domain_update.rb +++ b/lib/deserializers/xml/domain_update.rb @@ -42,20 +42,18 @@ module Deserializers end def nameservers - nameservers = [] - frame.css('add > ns > hostAttr').each do |ns| - nsrv = Deserializers::Xml::Nameserver.new(ns).call - nsrv[:action] = 'add' - nameservers << nsrv - end + @nameservers = [] - frame.css('rem > ns > hostAttr').each do |ns| - nsrv = Deserializers::Xml::Nameserver.new(ns).call - nsrv[:action] = 'rem' - nameservers << nsrv - end + frame.css('add > ns > hostAttr').each { |ns| assign_ns(ns) } + frame.css('rem > ns > hostAttr').each { |ns| assign_ns(ns, add: false) } - nameservers.presence + @nameservers.presence + end + + def assign_ns(nameserver, add: true) + nsrv = Deserializers::Xml::Nameserver.new(nameserver).call + nsrv[:action] = add ? 'add' : 'rem' + @nameservers << nsrv end def dns_keys @@ -72,17 +70,12 @@ module Deserializers def statuses return if frame.css('status').blank? - statuses = [] + s = [] - frame.css('add > status').each do |e| - statuses << { status: e.attr('s').to_s, action: 'add' } - end + frame.css('add > status').each { |e| s << { status: e.attr('s'), action: 'add' } } + frame.css('rem > status').each { |e| s << { status: e.attr('s'), action: 'rem' } } - frame.css('rem > status').each do |e| - statuses << { status: e.attr('s').to_s, action: 'rem' } - end - - statuses + s end def legal_document From e2ff5d45061a471c52754651d94d6844d4549cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 11 Jan 2021 15:57:23 +0200 Subject: [PATCH 16/80] REPP: Add Domain Create endpoint --- app/controllers/repp/v1/domains_controller.rb | 24 +++++++++++++++++++ app/models/actions/domain_create.rb | 13 ++++++---- app/models/epp/domain.rb | 2 +- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 283d2bf7b..0e16a90c1 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -3,6 +3,7 @@ module Repp module V1 class DomainsController < BaseController before_action :set_authorized_domain, only: %i[transfer_info] + before_action :forward_registrar_id, only: %i[create] before_action :set_domain, only: %i[show] def index @@ -17,6 +18,18 @@ module Repp render_success(data: { domain: Serializers::RegistrantApi::Domain.new(@domain).to_json }) end + ## POST /repp/v1/domains + def create + authorize!(:create, Epp::Domain) + puts params + @domain = Epp::Domain.new + action = Actions::DomainCreate.new(@domain, domain_create_params) + + handle_errors(@domain) and return unless action.call + + render_success(create_update_success_body) + end + def transfer_info contact_fields = %i[code name ident ident_type ident_country_code phone email street city zip country_code statuses] @@ -72,6 +85,10 @@ module Repp params.permit(:id) end + def forward_registrar_id + params[:domain][:registrar_id] = current_user.registrar.id + end + def set_domain @domain = Domain.find_by(registrar: current_user.registrar, name: params[:id]) end @@ -104,6 +121,13 @@ module Repp def index_params params.permit(:limit, :offset, :details) end + + def domain_create_params + params.require(:domain).require([:name, :registrant_id, :period, :period_unit]) + params.require(:domain).permit(:name, :registrant_id, :period, :period_unit, :registrar_id) + + end + end end end diff --git a/app/models/actions/domain_create.rb b/app/models/actions/domain_create.rb index ced9c2327..30f004ae3 100644 --- a/app/models/actions/domain_create.rb +++ b/app/models/actions/domain_create.rb @@ -64,11 +64,14 @@ module Actions end def assign_domain_attributes + puts "FOOOK" + puts params + puts "AYYYYY #{params[:name]}" domain.name = params[:name].strip.downcase domain.registrar = Registrar.find(params[:registrar_id]) assign_domain_period assign_domain_auth_codes - domain.dnskeys_attributes = params[:dnskeys_attributes] + domain.dnskeys_attributes = params[:dnskeys_attributes] if params[:dnskeys_attributes] end def assign_domain_auth_codes @@ -82,7 +85,7 @@ module Actions end def assign_nameservers - domain.nameservers_attributes = params[:nameservers_attributes] + domain.nameservers_attributes = params[:nameservers_attributes] if params[:nameservers_attributes] end def assign_contact(contact_code, admin: true) @@ -98,14 +101,16 @@ module Actions def assign_domain_contacts @admin_contacts = [] @tech_contacts = [] - params[:admin_domain_contacts_attributes].each { |c| assign_contact(c) } - params[:tech_domain_contacts_attributes].each { |c| assign_contact(c, admin: false) } + params[:admin_domain_contacts_attributes]&.each { |c| assign_contact(c) } + params[:tech_domain_contacts_attributes]&.each { |c| assign_contact(c, admin: false) } domain.admin_domain_contacts_attributes = @admin_contacts domain.tech_domain_contacts_attributes = @tech_contacts end def assign_expiry_time + return unless domain.period + period = Integer(domain.period) plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym exp = (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 99a3089a9..c4106e45a 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -31,7 +31,7 @@ class Epp::Domain < Domain # validate registrant here as well ([Contact.find_by(code: registrant.code)] + active_admins + active_techs).each do |x| unless x.valid? - add_epp_error('2304', nil, nil, I18n.t(:contact_is_not_valid, value: x.code)) + add_epp_error('2304', nil, nil, I18n.t(:contact_is_not_valid, value: x.try(:code))) ok = false end end From d4b84a58dfff515d9317a49c3f4427ee5ea51ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 11 Jan 2021 16:16:07 +0200 Subject: [PATCH 17/80] Fix disclosable scope when copying registrant to admin/tech --- app/models/epp/domain.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index c4106e45a..51bd4f8bc 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -110,8 +110,10 @@ class Epp::Domain < Domain def attach_default_contacts return if registrant.blank? - tech_contacts << registrant if tech_domain_contacts.blank? - admin_contacts << registrant if admin_domain_contacts.blank? && !registrant.org? + registrant_obj = Contact.find_by(code: registrant.code) + + tech_contacts << registrant_obj if tech_domain_contacts.blank? + admin_contacts << registrant_obj if admin_domain_contacts.blank? && !registrant.org? end def apply_pending_delete! From fcb97df45d10cab616f28bdfece8051c12fa68df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 11 Jan 2021 16:23:25 +0200 Subject: [PATCH 18/80] REPP: Fix domain create success response --- app/controllers/repp/v1/domains_controller.rb | 4 +--- app/models/actions/domain_create.rb | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 0e16a90c1..10a671ac8 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -21,13 +21,12 @@ module Repp ## POST /repp/v1/domains def create authorize!(:create, Epp::Domain) - puts params @domain = Epp::Domain.new action = Actions::DomainCreate.new(@domain, domain_create_params) handle_errors(@domain) and return unless action.call - render_success(create_update_success_body) + render_success(data: { domain: { name: @domain.name } }) end def transfer_info @@ -125,7 +124,6 @@ module Repp def domain_create_params params.require(:domain).require([:name, :registrant_id, :period, :period_unit]) params.require(:domain).permit(:name, :registrant_id, :period, :period_unit, :registrar_id) - end end diff --git a/app/models/actions/domain_create.rb b/app/models/actions/domain_create.rb index 30f004ae3..f028ec4ef 100644 --- a/app/models/actions/domain_create.rb +++ b/app/models/actions/domain_create.rb @@ -64,9 +64,6 @@ module Actions end def assign_domain_attributes - puts "FOOOK" - puts params - puts "AYYYYY #{params[:name]}" domain.name = params[:name].strip.downcase domain.registrar = Registrar.find(params[:registrar_id]) assign_domain_period From 2b3634b048afe4bc6ff9f66c86f6b81ae3eb84fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 18 Jan 2021 13:24:16 +0200 Subject: [PATCH 19/80] REPP domains: Nameserver actions --- Gemfile | 2 + Gemfile.lock | 3 + app/controllers/repp/v1/base_controller.rb | 2 +- .../repp/v1/domains/nameservers_controller.rb | 69 +++++++++++++++++++ app/controllers/repp/v1/domains_controller.rb | 55 +++++++++++++-- app/models/actions/domain_update.rb | 1 + app/models/concerns/epp_errors.rb | 2 + app/models/epp/domain.rb | 2 +- config/initializers/apipie.rb | 9 +++ config/routes.rb | 1 + 10 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 app/controllers/repp/v1/domains/nameservers_controller.rb create mode 100644 config/initializers/apipie.rb diff --git a/Gemfile b/Gemfile index 9bbcba254..531cad50a 100644 --- a/Gemfile +++ b/Gemfile @@ -92,3 +92,5 @@ group :test do gem 'webdrivers' gem 'webmock' end + +gem "apipie-rails", "~> 0.5.18" diff --git a/Gemfile.lock b/Gemfile.lock index 78a075243..c5be80f31 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -145,6 +145,8 @@ GEM akami (1.3.1) gyoku (>= 0.4.0) nokogiri + apipie-rails (0.5.18) + rails (>= 4.1) attr_required (1.0.1) autoprefixer-rails (10.0.0.2) execjs @@ -485,6 +487,7 @@ DEPENDENCIES active_interaction (~> 3.8) activerecord-import airbrake + apipie-rails (~> 0.5.18) bootsnap (>= 1.1.0) bootstrap-sass (~> 3.4) cancancan diff --git a/app/controllers/repp/v1/base_controller.rb b/app/controllers/repp/v1/base_controller.rb index 2814ce2da..053e1ac42 100644 --- a/app/controllers/repp/v1/base_controller.rb +++ b/app/controllers/repp/v1/base_controller.rb @@ -9,7 +9,7 @@ module Repp before_action :set_paper_trail_whodunnit - rescue_from ActionController::ParameterMissing do |exception| + rescue_from ActionController::ParameterMissing, Apipie::ParamInvalid, Apipie::ParamMissing do |exception| render json: { code: 2003, message: exception }, status: :bad_request end diff --git a/app/controllers/repp/v1/domains/nameservers_controller.rb b/app/controllers/repp/v1/domains/nameservers_controller.rb new file mode 100644 index 000000000..928f54ed4 --- /dev/null +++ b/app/controllers/repp/v1/domains/nameservers_controller.rb @@ -0,0 +1,69 @@ +module Repp + module V1 + module Domains + class NameserversController < BaseController + before_action :set_domain, only: %i[create destroy] + before_action :set_nameserver, only: %i[destroy] + + api :POST, '/repp/v1/domains/:domain_name/nameservers' + desc 'Creates new nameserver for domain' + param :nameservers, Array, required: true, desc: 'Array of new nameservers' do + param :hostname, String, required: true, desc: 'Nameserver hostname' + param :ipv4, Array, required: false, desc: 'Array of IPv4 values' + param :ipv6, Array, required: false, desc: 'Array of IPv6 values' + end + def create + nameserver_params[:nameservers].each { |n| n[:action] = 'add' } + action = Actions::DomainUpdate.new(@domain, params, current_user) + + unless action.call + handle_errors(@domain) + return + end + + render_success(data: { domain: { name: @domain.name } }) + end + + api :POST, '/repp/v1/domains/:domain/nameservers/:nameserver' + desc 'Modifiy nameserver for domain' + param :nameserver, Hash, required: true, desc: 'Nameserver parameters' do + param :hostname, String, required: true, desc: 'Nameserver hostname' + param :ipv4, Array, required: false, desc: 'Array of IPv4 values' + param :ipv6, Array, required: false, desc: 'Array of IPv6 values' + end + + api :DELETE, '/repp/v1/domains/:domain/nameservers/:nameserver' + desc 'Delete nameserver for domain' + def destroy + nameserver = { nameservers: [{ hostname: params[:id], action: 'rem' }] } + action = Actions::DomainUpdate.new(@domain, nameserver, current_user) + + unless action.call + handle_errors(@domain) + return + end + + render_success(data: { domain: { name: @domain.name } }) + end + + private + + def set_domain + registrar = current_user.registrar + @domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id]) + @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id]) + + @domain + end + + def set_nameserver + @nameserver = @domain.nameservers.find_by!(hostname: params[:id]) + end + + def nameserver_params + params.permit! + end + end + end + end +end diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 10a671ac8..524e4a3ee 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -4,7 +4,7 @@ module Repp class DomainsController < BaseController before_action :set_authorized_domain, only: %i[transfer_info] before_action :forward_registrar_id, only: %i[create] - before_action :set_domain, only: %i[show] + before_action :set_domain, only: %i[show update] def index records = current_user.registrar.domains @@ -18,7 +18,36 @@ module Repp render_success(data: { domain: Serializers::RegistrantApi::Domain.new(@domain).to_json }) end - ## POST /repp/v1/domains + api :POST, '/repp/v1/domains' + desc 'Creates new domain' + param :domain, Hash, required: true, desc: 'Parameters for new domain' do + param :name, String, required: true, desc: 'Domain name to be registered' + param :registrant_id, String, required: true, desc: 'Registrant contact code' + param :period, Integer, required: true, desc: 'Registration period in months or years' + param :period_unit, String, required: true, desc: 'Period type (month m) or (year y)' + param :nameservers_attributes, Array, required: false, desc: 'Domain nameservers' do + param :hostname, String, required: true, desc: 'Nameserver hostname' + param :ipv4, Array, desc: 'Array of IPv4 addresses' + param :ipv6, Array, desc: 'Array of IPv4 addresses' + end + param :admin_domain_contacts_attributes, Array, required: false, desc: 'Admin domain contacts codes' + param :admin_domain_contacts_attributes, Array, required: false, desc: 'Tech domain contacts codes' + param :dnskeys_attributes, Array, required: false, desc: 'DNSSEC keys for domain' do + param :flags, String, required: true, desc: 'Flag of DNSSEC key' + param :protocol, String, required: true, desc: 'Protocol of DNSSEC key' + param :alg, String, required: true, desc: 'Algorithm of DNSSEC key' + param :public_key, String, required: true, desc: 'Public key of DNSSEC key' + end + end + returns code: 200, desc: 'Successful domain registration response' do + property :code, Integer, desc: 'EPP code' + property :message, String, desc: 'EPP code explanation' + property :data, Hash do + property :domain, Hash do + property :name, String, 'Domain name' + end + end + end def create authorize!(:create, Epp::Domain) @domain = Epp::Domain.new @@ -29,6 +58,25 @@ module Repp render_success(data: { domain: { name: @domain.name } }) end + api :PUT, 'repp/v1/domains/:id' + param :id, String, desc: 'Domain name in IDN / Puny format' + param :domain, Hash, required: true, desc: 'Changes of domain object' do + param :registrant, Hash, required: false, desc: 'New registrant object' do + param :code, String, required: true, desc: 'New registrant contact code' + end + param :auth_info, String, required: false, desc: 'New authorization code' + end + def update + action = Actions::DomainUpdate.new(@domain, params[:domain], current_user) + + unless action.call + handle_errors(@domain) + return + end + + render_success(data: { domain: { name: @domain.name } }) + end + def transfer_info contact_fields = %i[code name ident ident_type ident_country_code phone email street city zip country_code statuses] @@ -89,7 +137,7 @@ module Repp end def set_domain - @domain = Domain.find_by(registrar: current_user.registrar, name: params[:id]) + @domain = Epp::Domain.find_by!(registrar: current_user.registrar, name: params[:id]) end def set_authorized_domain @@ -125,7 +173,6 @@ module Repp params.require(:domain).require([:name, :registrant_id, :period, :period_unit]) params.require(:domain).permit(:name, :registrant_id, :period, :period_unit, :registrar_id) end - end end end diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index 176a9831b..e8209ac50 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -55,6 +55,7 @@ module Actions end def assign_nameserver_modifications + puts "ASSIGNING" @nameservers = [] params[:nameservers].each do |ns_attr| case ns_attr[:action] diff --git a/app/models/concerns/epp_errors.rb b/app/models/concerns/epp_errors.rb index c1e4fa2e1..d12080158 100644 --- a/app/models/concerns/epp_errors.rb +++ b/app/models/concerns/epp_errors.rb @@ -86,6 +86,8 @@ module EppErrors end end nil + rescue NameError + nil end def construct_msg_args_and_value(epp_error_args) diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 51bd4f8bc..0ba8ceec5 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -29,7 +29,7 @@ class Epp::Domain < Domain active_techs = tech_domain_contacts.select { |x| !x.marked_for_destruction? } # validate registrant here as well - ([Contact.find_by(code: registrant.code)] + active_admins + active_techs).each do |x| + ([Contact.find(registrant.id)] + active_admins + active_techs).each do |x| unless x.valid? add_epp_error('2304', nil, nil, I18n.t(:contact_is_not_valid, value: x.try(:code))) ok = false diff --git a/config/initializers/apipie.rb b/config/initializers/apipie.rb new file mode 100644 index 000000000..f835ce54f --- /dev/null +++ b/config/initializers/apipie.rb @@ -0,0 +1,9 @@ +Apipie.configure do |config| + config.app_name = "DomainNameRegistry" + config.validate = true + config.translate = false + config.api_base_url = "/api" + config.doc_base_url = "/apipie" + # where is your API defined? + config.api_controllers_matcher = "#{Rails.root}/app/controllers/**/*.rb" +end diff --git a/config/routes.rb b/config/routes.rb index eb062ca31..b0a17caf5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -60,6 +60,7 @@ Rails.application.routes.draw do end end resources :domains, constraints: { id: /.*/ } do + resources :nameservers, only: %i[create destroy], constraints: { id: /.*/ }, controller: 'domains/nameservers' collection do get ':id/transfer_info', to: 'domains#transfer_info', constraints: { id: /.*/ } post 'transfer', to: 'domains#transfer' From 9dcd40ee3b19355b98bac2d4295f53ad8493d266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 18 Jan 2021 16:36:07 +0200 Subject: [PATCH 20/80] REPP domains: Modify DNSSEC keys --- .../repp/v1/domains/dnssec_controller.rb | 70 +++++++++++++++++++ .../repp/v1/domains/nameservers_controller.rb | 4 +- app/controllers/repp/v1/domains_controller.rb | 1 + app/models/actions/domain_update.rb | 8 +-- config/routes.rb | 2 + 5 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 app/controllers/repp/v1/domains/dnssec_controller.rb diff --git a/app/controllers/repp/v1/domains/dnssec_controller.rb b/app/controllers/repp/v1/domains/dnssec_controller.rb new file mode 100644 index 000000000..29cc39f80 --- /dev/null +++ b/app/controllers/repp/v1/domains/dnssec_controller.rb @@ -0,0 +1,70 @@ +module Repp + module V1 + module Domains + class DnssecController < BaseController + before_action :set_domain, only: %i[index create destroy] + + api :GET, '/repp/v1/domains/:domain_name/dnssec' + desc "View all domain's DNSSEC keys" + def index + dnssec_keys = @domain.dnskeys + data = { dns_keys: dnssec_keys.as_json(only: %i[flags alg protocol public_key]) } + render_success(data: data) + end + + api :POST, '/repp/v1/domains/:domain_name/dnssec' + desc 'Add new DNSSEC key(s) to domain' + param :dns_keys, Array, required: true, desc: 'Array of new DNSSEC keys' do + param :flags, String, required: true, desc: '256 (KSK) or 257 (ZSK)' + param :protocol, String, required: true, desc: 'Key protocol (3)' + param :alg, String, required: true, desc: 'DNSSEC key algorithm (3,5,6,7,8,10,13,14)' + param :public_key, String, required: true, desc: 'DNSSEC public key' + end + def create + dnssec_params[:dnssec][:dns_keys].each { |n| n[:action] = 'add' } + action = Actions::DomainUpdate.new(@domain, dnssec_params[:dnssec], current_user) + + unless action.call + handle_errors(@domain) + return + end + + render_success(data: { domain: { name: @domain.name } }) + end + + api :DELETE, 'repp/v1/domains/:domain_name/dnssec' + param :dns_keys, Array, required: true, desc: 'Array of removable DNSSEC keys' do + param :flags, String, required: true, desc: '256 (KSK) or 257 (ZSK)' + param :protocol, String, required: true, desc: 'Key protocol (3)' + param :alg, String, required: true, desc: 'DNSSEC key algorithm (3,5,6,7,8,10,13,14)' + param :public_key, String, required: true, desc: 'DNSSEC public key' + end + def destroy + dnssec_params[:dnssec][:dns_keys].each { |n| n[:action] = 'rem' } + action = Actions::DomainUpdate.new(@domain, dnssec_params[:dnssec], current_user) + + unless action.call + handle_errors(@domain) + return + end + + render_success(data: { domain: { name: @domain.name } }) + end + + private + + def set_domain + registrar = current_user.registrar + @domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id]) + @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id]) + + @domain + end + + def dnssec_params + params.permit! + end + end + end + end +end diff --git a/app/controllers/repp/v1/domains/nameservers_controller.rb b/app/controllers/repp/v1/domains/nameservers_controller.rb index 928f54ed4..acbc026fa 100644 --- a/app/controllers/repp/v1/domains/nameservers_controller.rb +++ b/app/controllers/repp/v1/domains/nameservers_controller.rb @@ -24,8 +24,8 @@ module Repp render_success(data: { domain: { name: @domain.name } }) end - api :POST, '/repp/v1/domains/:domain/nameservers/:nameserver' - desc 'Modifiy nameserver for domain' + api :PUT, '/repp/v1/domains/:domain/nameservers/:nameserver' + desc 'Modify nameserver for domain' param :nameserver, Hash, required: true, desc: 'Nameserver parameters' do param :hostname, String, required: true, desc: 'Nameserver hostname' param :ipv4, Array, required: false, desc: 'Array of IPv4 values' diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 524e4a3ee..3d46e1d99 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -63,6 +63,7 @@ module Repp param :domain, Hash, required: true, desc: 'Changes of domain object' do param :registrant, Hash, required: false, desc: 'New registrant object' do param :code, String, required: true, desc: 'New registrant contact code' + param :verified, [true, false], required: false, desc: 'Registrant change is already verified' end param :auth_info, String, required: false, desc: 'New authorization code' end diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index e8209ac50..7dbdbd336 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -55,7 +55,6 @@ module Actions end def assign_nameserver_modifications - puts "ASSIGNING" @nameservers = [] params[:nameservers].each do |ns_attr| case ns_attr[:action] @@ -80,17 +79,16 @@ module Actions def assign_dnssec_modifications @dnskeys = [] - params[:dns_keys].each do |key| case key[:action] when 'add' - validate_dnskey_integrity(key) && @dnskeys << key.except(:action) + validate_dnskey_integrity(key) when 'rem' assign_removable_dnskey(key) end end - domain.dnskeys_attributes = @dnskeys + domain.dnskeys_attributes = @dnskeys.uniq end def validate_dnskey_integrity(key) @@ -100,7 +98,7 @@ module Actions domain.add_epp_error('2306', nil, nil, %i[dnskeys ds_data_not_allowed]) end - dnskeys << key.except(:action) + @dnskeys << key.except(:action) end def assign_removable_dnskey(key) diff --git a/config/routes.rb b/config/routes.rb index b0a17caf5..4fbed13aa 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -61,6 +61,8 @@ Rails.application.routes.draw do end resources :domains, constraints: { id: /.*/ } do resources :nameservers, only: %i[create destroy], constraints: { id: /.*/ }, controller: 'domains/nameservers' + resources :dnssec, only: %i[index create], constraints: { id: /.*/ }, controller: 'domains/dnssec' + match "dnssec", to: "domains/dnssec#destroy", via: "delete", defaults: { id: nil } collection do get ':id/transfer_info', to: 'domains#transfer_info', constraints: { id: /.*/ } post 'transfer', to: 'domains#transfer' From fda58e9a410f22c07766f05040b63e2ae3f9eee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 18 Jan 2021 17:23:31 +0200 Subject: [PATCH 21/80] REPP Domains: Allow create/read/update for domain-scoped contacts --- .../repp/v1/domains/contacts_controller.rb | 59 +++++++++++++++++++ app/models/actions/domain_update.rb | 2 +- config/routes.rb | 2 + 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/app/controllers/repp/v1/domains/contacts_controller.rb b/app/controllers/repp/v1/domains/contacts_controller.rb index 75404e0c6..631916a67 100644 --- a/app/controllers/repp/v1/domains/contacts_controller.rb +++ b/app/controllers/repp/v1/domains/contacts_controller.rb @@ -4,6 +4,53 @@ module Repp class ContactsController < BaseController before_action :set_current_contact, only: [:update] before_action :set_new_contact, only: [:update] + before_action :set_domain, only: %i[index create destroy] + + api :GET, '/repp/v1/domains/:domain_name/contacts' + desc "View domain's admin and tech contacts" + def index + admin_contacts = @domain.admin_domain_contacts.pluck(:contact_code_cache) + tech_contacts = @domain.tech_domain_contacts.pluck(:contact_code_cache) + + data = { admin_contacts: admin_contacts, tech_contacts: tech_contacts } + render_success(data: data) + end + + api :POST, '/repp/v1/domains/:domain_name/contacts' + desc "Link new contact(s) to domain" + param :contacts, Array, required: true, desc: 'Array of new linked contacts' do + param :code, String, required: true, desc: 'Contact code' + param :type, String, required: true, desc: 'Role of contact (admin/tech)' + end + def create + contact_create_params[:contacts].each { |c| c[:action] = 'add' } + action = Actions::DomainUpdate.new(@domain, contact_create_params, current_user) + + unless action.call + handle_errors(@domain) + return + end + + render_success(data: { domain: { name: @domain.name } }) + end + + api :DELETE, '/repp/v1/domains/:domain_name/contacts' + desc "Remove contact(s) from domain" + param :contacts, Array, required: true, desc: 'Array of new linked contacts' do + param :code, String, required: true, desc: 'Contact code' + param :type, String, required: true, desc: 'Role of contact (admin/tech)' + end + def destroy + contact_create_params[:contacts].each { |c| c[:action] = 'rem' } + action = Actions::DomainUpdate.new(@domain, contact_create_params, current_user) + + unless action.call + handle_errors(@domain) + return + end + + render_success(data: { domain: { name: @domain.name } }) + end def set_current_contact @current_contact = current_user.registrar.contacts.find_by!( @@ -32,6 +79,18 @@ module Repp private + def set_domain + registrar = current_user.registrar + @domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id]) + @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id]) + + @domain + end + + def contact_create_params + params.permit! + end + def contact_params params.require(%i[current_contact_id new_contact_id]) params.permit(:current_contact_id, :new_contact_id) diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index 7dbdbd336..4b4549286 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -154,7 +154,7 @@ module Actions def assign_contact(obj, add: false, admin: true, code:) if obj.blank? domain.add_epp_error('2303', 'contact', code, %i[domain_contacts not_found]) - elsif obj.org? && admin + elsif obj.try(:org?) && admin && add domain.add_epp_error('2306', 'contact', code, %i[domain_contacts admin_contact_can_be_only_private_person]) else diff --git a/config/routes.rb b/config/routes.rb index 4fbed13aa..bcef0fa8d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -62,7 +62,9 @@ Rails.application.routes.draw do resources :domains, constraints: { id: /.*/ } do resources :nameservers, only: %i[create destroy], constraints: { id: /.*/ }, controller: 'domains/nameservers' resources :dnssec, only: %i[index create], constraints: { id: /.*/ }, controller: 'domains/dnssec' + resources :contacts, only: %i[index create], constraints: { id: /.*/ }, controller: 'domains/contacts' match "dnssec", to: "domains/dnssec#destroy", via: "delete", defaults: { id: nil } + match "contacts", to: "domains/contacts#destroy", via: "delete", defaults: { id: nil } collection do get ':id/transfer_info', to: 'domains#transfer_info', constraints: { id: /.*/ } post 'transfer', to: 'domains#transfer' From 454433cf105400f138b4f8e95b2eb8d497fee10e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 21 Jan 2021 09:55:09 +0200 Subject: [PATCH 22/80] REPP: Update ApiDoc --- .../repp/v1/accounts_controller.rb | 3 ++ .../repp/v1/contacts_controller.rb | 17 +++++++---- .../repp/v1/domains/dnssec_controller.rb | 4 +-- .../repp/v1/domains/nameservers_controller.rb | 12 ++------ .../repp/v1/domains/renews_controller.rb | 30 +++++++++++++++++++ app/controllers/repp/v1/domains_controller.rb | 17 ++++++++--- config/initializers/apipie.rb | 7 +++-- config/routes.rb | 1 + 8 files changed, 67 insertions(+), 24 deletions(-) diff --git a/app/controllers/repp/v1/accounts_controller.rb b/app/controllers/repp/v1/accounts_controller.rb index 89c14808f..00f70ea63 100644 --- a/app/controllers/repp/v1/accounts_controller.rb +++ b/app/controllers/repp/v1/accounts_controller.rb @@ -1,6 +1,9 @@ module Repp module V1 class AccountsController < BaseController + + api :GET, '/repp/v1/accounts/balance' + desc "Get account's balance" def balance resp = { balance: current_user.registrar.cash_account.balance, currency: current_user.registrar.cash_account.currency } diff --git a/app/controllers/repp/v1/contacts_controller.rb b/app/controllers/repp/v1/contacts_controller.rb index acf275c47..f3e40a119 100644 --- a/app/controllers/repp/v1/contacts_controller.rb +++ b/app/controllers/repp/v1/contacts_controller.rb @@ -4,7 +4,8 @@ module Repp class ContactsController < BaseController before_action :find_contact, only: %i[show update destroy] - ## GET /repp/v1/contacts + api :get, '/repp/v1/contacts' + desc 'Get all existing contacts' def index record_count = current_user.registrar.contacts.count contacts = showable_contacts(params[:details], params[:limit] || 200, @@ -13,14 +14,16 @@ module Repp render(json: @response, status: :ok) end - ## GET /repp/v1/contacts/1 + api :get, '/repp/v1/contacts/:contact_code' + desc 'Get a specific contact' def show serializer = ::Serializers::Repp::Contact.new(@contact, show_address: Contact.address_processing?) render_success(data: serializer.to_json) end - ## GET /repp/v1/contacts/check/1 + api :get, '/repp/v1/contacts/check/:contact_code' + desc 'Check contact code availability' def check contact = Epp::Contact.find_by(code: params[:id]) data = { contact: { id: params[:id], available: contact.nil? } } @@ -28,7 +31,8 @@ module Repp render_success(data: data) end - ## POST /repp/v1/contacts + api :POST, '/repp/v1/contacts' + desc 'Create a new contact' def create @contact = Epp::Contact.new(contact_params_with_address, current_user.registrar, epp: false) action = Actions::ContactCreate.new(@contact, params[:legal_document], @@ -42,7 +46,8 @@ module Repp render_success(create_update_success_body) end - ## PUT /repp/v1/contacts/1 + api :PUT, '/repp/v1/contacts/:contact_code' + desc 'Update existing contact' def update action = Actions::ContactUpdate.new(@contact, contact_params_with_address(required: false), params[:legal_document], @@ -56,6 +61,8 @@ module Repp render_success(create_update_success_body) end + api :DELETE, '/repp/v1/contacts/:contact_code' + desc 'Delete a specific contact' def destroy action = Actions::ContactDelete.new(@contact, params[:legal_document]) unless action.call diff --git a/app/controllers/repp/v1/domains/dnssec_controller.rb b/app/controllers/repp/v1/domains/dnssec_controller.rb index 29cc39f80..5d352dc3e 100644 --- a/app/controllers/repp/v1/domains/dnssec_controller.rb +++ b/app/controllers/repp/v1/domains/dnssec_controller.rb @@ -5,7 +5,7 @@ module Repp before_action :set_domain, only: %i[index create destroy] api :GET, '/repp/v1/domains/:domain_name/dnssec' - desc "View all domain's DNSSEC keys" + desc "View specific domain's DNSSEC keys" def index dnssec_keys = @domain.dnskeys data = { dns_keys: dnssec_keys.as_json(only: %i[flags alg protocol public_key]) } @@ -13,7 +13,7 @@ module Repp end api :POST, '/repp/v1/domains/:domain_name/dnssec' - desc 'Add new DNSSEC key(s) to domain' + desc 'Create a new DNSSEC key(s) for domain' param :dns_keys, Array, required: true, desc: 'Array of new DNSSEC keys' do param :flags, String, required: true, desc: '256 (KSK) or 257 (ZSK)' param :protocol, String, required: true, desc: 'Key protocol (3)' diff --git a/app/controllers/repp/v1/domains/nameservers_controller.rb b/app/controllers/repp/v1/domains/nameservers_controller.rb index acbc026fa..e307bb1d6 100644 --- a/app/controllers/repp/v1/domains/nameservers_controller.rb +++ b/app/controllers/repp/v1/domains/nameservers_controller.rb @@ -6,7 +6,7 @@ module Repp before_action :set_nameserver, only: %i[destroy] api :POST, '/repp/v1/domains/:domain_name/nameservers' - desc 'Creates new nameserver for domain' + desc 'Create new nameserver for domain' param :nameservers, Array, required: true, desc: 'Array of new nameservers' do param :hostname, String, required: true, desc: 'Nameserver hostname' param :ipv4, Array, required: false, desc: 'Array of IPv4 values' @@ -24,16 +24,8 @@ module Repp render_success(data: { domain: { name: @domain.name } }) end - api :PUT, '/repp/v1/domains/:domain/nameservers/:nameserver' - desc 'Modify nameserver for domain' - param :nameserver, Hash, required: true, desc: 'Nameserver parameters' do - param :hostname, String, required: true, desc: 'Nameserver hostname' - param :ipv4, Array, required: false, desc: 'Array of IPv4 values' - param :ipv6, Array, required: false, desc: 'Array of IPv6 values' - end - api :DELETE, '/repp/v1/domains/:domain/nameservers/:nameserver' - desc 'Delete nameserver for domain' + desc 'Delete specific nameserver from domain' def destroy nameserver = { nameservers: [{ hostname: params[:id], action: 'rem' }] } action = Actions::DomainUpdate.new(@domain, nameserver, current_user) diff --git a/app/controllers/repp/v1/domains/renews_controller.rb b/app/controllers/repp/v1/domains/renews_controller.rb index 6b016dd86..67c537bf6 100644 --- a/app/controllers/repp/v1/domains/renews_controller.rb +++ b/app/controllers/repp/v1/domains/renews_controller.rb @@ -4,6 +4,24 @@ module Repp class RenewsController < BaseController before_action :validate_renew_period, only: [:bulk_renew] before_action :select_renewable_domains, only: [:bulk_renew] + before_action :set_domain, only: [:create] + + api :POST, 'repp/v1/domains/:domain_name/renew' + desc 'Renew domain' + param :renew, Hash, required: true, desc: 'Renew parameters' do + param :renew_period, Integer, required: true, desc: 'Renew period. Month (m) or year (y)' + param :period_unit, String, required: true, desc: 'For how many months or years to renew' + end + def create + action = Actions::DomainUpdate.new(@domain, renew_params[:renew], current_user) + + unless action.call + handle_errors(@domain) + return + end + + render_success(data: { domain: { name: @domain.name } }) + end def bulk_renew renew = run_bulk_renew_task(@domains, bulk_renew_params[:renew_period]) @@ -16,6 +34,18 @@ module Repp private + def set_domain + registrar = current_user.registrar + @domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id]) + @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id]) + + @domain + end + + def renew_params + params.permit! + end + def validate_renew_period @epp_errors ||= [] periods = Depp::Domain::PERIODS.map { |p| p[1] } diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 3d46e1d99..06849fb7f 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -6,6 +6,8 @@ module Repp before_action :forward_registrar_id, only: %i[create] before_action :set_domain, only: %i[show update] + api :GET, '/repp/v1/domains' + desc 'Get all existing domains' def index records = current_user.registrar.domains domains = records.limit(limit).offset(offset) @@ -14,12 +16,14 @@ module Repp render_success(data: { domains: domains, total_number_of_records: records.count }) end + api :GET, '/repp/v1/domains/:domain_name' + desc 'Get a specific domain' def show render_success(data: { domain: Serializers::RegistrantApi::Domain.new(@domain).to_json }) end api :POST, '/repp/v1/domains' - desc 'Creates new domain' + desc 'Create a new domain' param :domain, Hash, required: true, desc: 'Parameters for new domain' do param :name, String, required: true, desc: 'Domain name to be registered' param :registrant_id, String, required: true, desc: 'Registrant contact code' @@ -58,7 +62,8 @@ module Repp render_success(data: { domain: { name: @domain.name } }) end - api :PUT, 'repp/v1/domains/:id' + api :PUT, '/repp/v1/domains/:domain_name' + desc 'Update existing domain' param :id, String, desc: 'Domain name in IDN / Puny format' param :domain, Hash, required: true, desc: 'Changes of domain object' do param :registrant, Hash, required: false, desc: 'New registrant object' do @@ -78,6 +83,8 @@ module Repp render_success(data: { domain: { name: @domain.name } }) end + api :GET, '/repp/v1/domains/:domain_name/transfer_info' + desc "Retrieve specific domain's transfer info" def transfer_info contact_fields = %i[code name ident ident_type ident_country_code phone email street city zip country_code statuses] @@ -92,6 +99,8 @@ module Repp render_success(data: data) end + api :POST, '/repp/v1/domains/:domain_name/transfer' + desc 'Transfer specific domain' def transfer @errors ||= [] @successful = [] @@ -103,6 +112,8 @@ module Repp render_success(data: { success: @successful, failed: @errors }) end + private + def initiate_transfer(transfer) domain = Epp::Domain.find_or_initialize_by(name: transfer[:domain_name]) action = Actions::DomainTransfer.new(domain, transfer[:transfer_code], @@ -116,8 +127,6 @@ module Repp end end - private - def transfer_params params.require(:data).require(:domain_transfers).each do |t| t.require(:domain_name) diff --git a/config/initializers/apipie.rb b/config/initializers/apipie.rb index f835ce54f..6fc794b12 100644 --- a/config/initializers/apipie.rb +++ b/config/initializers/apipie.rb @@ -1,9 +1,10 @@ Apipie.configure do |config| - config.app_name = "DomainNameRegistry" + config.app_name = "Estonian Internet Foundation's REST EPP" config.validate = true config.translate = false - config.api_base_url = "/api" - config.doc_base_url = "/apipie" + config.api_base_url = "/api" + config.doc_base_url = "/apipie" + config.swagger_content_type_input = :json # where is your API defined? config.api_controllers_matcher = "#{Rails.root}/app/controllers/**/*.rb" end diff --git a/config/routes.rb b/config/routes.rb index bcef0fa8d..32d5b83fb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -63,6 +63,7 @@ Rails.application.routes.draw do resources :nameservers, only: %i[create destroy], constraints: { id: /.*/ }, controller: 'domains/nameservers' resources :dnssec, only: %i[index create], constraints: { id: /.*/ }, controller: 'domains/dnssec' resources :contacts, only: %i[index create], constraints: { id: /.*/ }, controller: 'domains/contacts' + resources :renew, only: %i[create], constraints: { id: /.*/ }, controller: 'domains/renews' match "dnssec", to: "domains/dnssec#destroy", via: "delete", defaults: { id: nil } match "contacts", to: "domains/contacts#destroy", via: "delete", defaults: { id: nil } collection do From dcb55a1af9e929c5ef3cf67de26986c66ce329d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 21 Jan 2021 13:08:54 +0200 Subject: [PATCH 23/80] Create domain renew action --- .../repp/v1/domains/renews_controller.rb | 5 +-- app/models/actions/domain_renew.rb | 33 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 app/models/actions/domain_renew.rb diff --git a/app/controllers/repp/v1/domains/renews_controller.rb b/app/controllers/repp/v1/domains/renews_controller.rb index 67c537bf6..1ba8db506 100644 --- a/app/controllers/repp/v1/domains/renews_controller.rb +++ b/app/controllers/repp/v1/domains/renews_controller.rb @@ -9,11 +9,12 @@ module Repp api :POST, 'repp/v1/domains/:domain_name/renew' desc 'Renew domain' param :renew, Hash, required: true, desc: 'Renew parameters' do - param :renew_period, Integer, required: true, desc: 'Renew period. Month (m) or year (y)' + param :period, Integer, required: true, desc: 'Renew period. Month (m) or year (y)' param :period_unit, String, required: true, desc: 'For how many months or years to renew' end def create - action = Actions::DomainUpdate.new(@domain, renew_params[:renew], current_user) + authorize!(:renew, @domain) + action = Actions::DomainRenew.new(@domain, renew_params[:renew], current_user.registrar) unless action.call handle_errors(@domain) diff --git a/app/models/actions/domain_renew.rb b/app/models/actions/domain_renew.rb new file mode 100644 index 000000000..ec8178e6f --- /dev/null +++ b/app/models/actions/domain_renew.rb @@ -0,0 +1,33 @@ +module Actions + class DomainRenew + attr_reader :domain + attr_reader :params + attr_reader :user + + def initialize(domain, params, user) + @domain = domain + @params = params + @user = user + end + + def call + renew + end + + def renew + period = params[:period] + unit = params[:period_unit] + + task = Domains::BulkRenew::SingleDomainRenew.run(domain: domain, + period: params[:period], + unit: params[:period_unit], + registrar: user) + + return true if task + + puts task.errors + + false + end + end +end From 349df32e95b0c0306a3b2f7af63e30b68cbd5507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 21 Jan 2021 14:00:59 +0200 Subject: [PATCH 24/80] Improve renew action --- app/controllers/repp/v1/domains/renews_controller.rb | 4 +++- app/models/actions/domain_renew.rb | 9 +-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/app/controllers/repp/v1/domains/renews_controller.rb b/app/controllers/repp/v1/domains/renews_controller.rb index 1ba8db506..e77c2e2d0 100644 --- a/app/controllers/repp/v1/domains/renews_controller.rb +++ b/app/controllers/repp/v1/domains/renews_controller.rb @@ -40,7 +40,9 @@ module Repp @domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id]) @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id]) - @domain + return @domain if @domain + + raise ActiveRecord::RecordNotFound end def renew_params diff --git a/app/models/actions/domain_renew.rb b/app/models/actions/domain_renew.rb index ec8178e6f..3e9740335 100644 --- a/app/models/actions/domain_renew.rb +++ b/app/models/actions/domain_renew.rb @@ -15,19 +15,12 @@ module Actions end def renew - period = params[:period] - unit = params[:period_unit] - task = Domains::BulkRenew::SingleDomainRenew.run(domain: domain, period: params[:period], unit: params[:period_unit], registrar: user) - return true if task - - puts task.errors - - false + task.valid? end end end From f26dd52fb044a46c4ca62c9bd9bbff8501c5d8b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 22 Jan 2021 10:48:55 +0200 Subject: [PATCH 25/80] EPP Renew: Use action instead --- app/controllers/epp/domains_controller.rb | 44 +++++------------------ 1 file changed, 8 insertions(+), 36 deletions(-) diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index 9cded2f75..b8fafb8a7 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -78,42 +78,14 @@ module Epp def renew authorize! :renew, @domain - period_element = params[:parsed_frame].css('period').text - period = (period_element.to_i == 0) ? 1 : period_element.to_i - period_unit = Epp::Domain.parse_period_unit_from_frame(params[:parsed_frame]) || 'y' - - balance_ok?('renew', period, period_unit) # loading pricelist - - begin - ActiveRecord::Base.transaction(isolation: :serializable) do - @domain.reload - - success = @domain.renew( - params[:parsed_frame].css('curExpDate').text, - period, period_unit - ) - - if success - unless balance_ok?('renew', period, period_unit) - handle_errors - fail ActiveRecord::Rollback - end - - current_user.registrar.debit!({ - sum: @domain_pricelist.price.amount, - description: "#{I18n.t('renew')} #{@domain.name}", - activity_type: AccountActivity::RENEW, - price: @domain_pricelist - }) - - render_epp_response '/epp/domains/renew' - else - handle_errors(@domain) - end - end - rescue ActiveRecord::StatementInvalid => e - sleep rand / 100 - retry + registrar_id = current_user.registrar.id + renew_params = ::Deserializers::Xml::Domain.new(params[:parsed_frame], + registrar_id).call + action = Actions::DomainRenew.new(@domain, renew_params, current_user.registrar) + if action.call + render_epp_response '/epp/domains/renew' + else + handle_errors(@domain) end end From 1d9850fb98d685e392fda0266db4ba7a49342699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 22 Jan 2021 10:49:21 +0200 Subject: [PATCH 26/80] Fix REPP log locale issue --- app/controllers/epp/domains_controller.rb | 1 + app/interactions/domains/check_balance/single_domain.rb | 2 ++ app/views/admin/repp_logs/show.haml | 2 +- config/locales/admin/repp_logs.en.yml | 2 ++ 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index b8fafb8a7..546cc131b 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -77,6 +77,7 @@ module Epp def renew authorize! :renew, @domain + @domain.validate_exp_dates(params[:parsed_frame].css('curExpDate').text) registrar_id = current_user.registrar.id renew_params = ::Deserializers::Xml::Domain.new(params[:parsed_frame], diff --git a/app/interactions/domains/check_balance/single_domain.rb b/app/interactions/domains/check_balance/single_domain.rb index 166edc4e3..365b69d6c 100644 --- a/app/interactions/domains/check_balance/single_domain.rb +++ b/app/interactions/domains/check_balance/single_domain.rb @@ -13,6 +13,8 @@ module Domains errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain, domain: domain.name)) + + domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) false end diff --git a/app/views/admin/repp_logs/show.haml b/app/views/admin/repp_logs/show.haml index bbaae977f..9bb9ea52e 100644 --- a/app/views/admin/repp_logs/show.haml +++ b/app/views/admin/repp_logs/show.haml @@ -1,6 +1,6 @@ - content_for :actions do = link_to(t(:back), :back, class: 'btn btn-primary') -= render 'shared/title', name: t(:repp_log) += render 'shared/title', name: t('.title') .row .col-md-12 diff --git a/config/locales/admin/repp_logs.en.yml b/config/locales/admin/repp_logs.en.yml index 559ae234a..2436f849a 100644 --- a/config/locales/admin/repp_logs.en.yml +++ b/config/locales/admin/repp_logs.en.yml @@ -4,3 +4,5 @@ en: index: title: REPP log reset_btn: Reset + show: + title: REPP log From 06088e33c5a3a46c9820f681711450fba200e8dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 22 Jan 2021 12:18:17 +0200 Subject: [PATCH 27/80] REPP: Specific domain transfer action --- .../repp/v1/domains/transfers_controller.rb | 38 +++++++++++++++++++ app/controllers/repp/v1/domains_controller.rb | 8 ++-- .../domains/check_balance/single_domain.rb | 5 +-- config/routes.rb | 1 + 4 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 app/controllers/repp/v1/domains/transfers_controller.rb diff --git a/app/controllers/repp/v1/domains/transfers_controller.rb b/app/controllers/repp/v1/domains/transfers_controller.rb new file mode 100644 index 000000000..be1f754c2 --- /dev/null +++ b/app/controllers/repp/v1/domains/transfers_controller.rb @@ -0,0 +1,38 @@ +module Repp + module V1 + module Domains + class TransfersController < BaseController + before_action :set_domain, only: [:create] + + api :POST, 'repp/v1/domains/:domain_name/transfer' + desc 'Transfer a specific domain' + param :transfer, Hash, required: true, desc: 'Renew parameters' do + param :transfer_code, String, required: true, desc: 'Renew period. Month (m) or year (y)' + end + def create + action = Actions::DomainTransfer.new(@domain, transfer_params[:transfer][:transfer_code], + current_user.registrar) + + unless action.call + handle_errors(@domain) + return + end + + render_success(data: { domain: { name: @domain.name, type: 'domain_transfer' } }) + end + + private + + def set_domain + h = {} + h[transfer_params[:domain_id].match?(/\A[0-9]+\z/) ? :id : :name] = transfer_params[:domain_id] + @domain = Epp::Domain.find_by!(h) + end + + def transfer_params + params.permit! + end + end + end + end +end diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 06849fb7f..a63f40402 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -99,8 +99,8 @@ module Repp render_success(data: data) end - api :POST, '/repp/v1/domains/:domain_name/transfer' - desc 'Transfer specific domain' + api :POST, '/repp/v1/domains/transfer' + desc 'Transfer multiple domains' def transfer @errors ||= [] @successful = [] @@ -112,8 +112,6 @@ module Repp render_success(data: { success: @successful, failed: @errors }) end - private - def initiate_transfer(transfer) domain = Epp::Domain.find_or_initialize_by(name: transfer[:domain_name]) action = Actions::DomainTransfer.new(domain, transfer[:transfer_code], @@ -127,6 +125,8 @@ module Repp end end + private + def transfer_params params.require(:data).require(:domain_transfers).each do |t| t.require(:domain_name) diff --git a/app/interactions/domains/check_balance/single_domain.rb b/app/interactions/domains/check_balance/single_domain.rb index 365b69d6c..de8f24d18 100644 --- a/app/interactions/domains/check_balance/single_domain.rb +++ b/app/interactions/domains/check_balance/single_domain.rb @@ -11,10 +11,9 @@ module Domains def execute return domain_pricelist.price.amount if domain_pricelist.try(:price) - errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain, - domain: domain.name)) - domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) + errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain, + domain: domain.name)) false end diff --git a/config/routes.rb b/config/routes.rb index 32d5b83fb..0bd0da82e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -64,6 +64,7 @@ Rails.application.routes.draw do resources :dnssec, only: %i[index create], constraints: { id: /.*/ }, controller: 'domains/dnssec' resources :contacts, only: %i[index create], constraints: { id: /.*/ }, controller: 'domains/contacts' resources :renew, only: %i[create], constraints: { id: /.*/ }, controller: 'domains/renews' + resources :transfer, only: %i[create], constraints: { id: /.*/ }, controller: 'domains/transfers' match "dnssec", to: "domains/dnssec#destroy", via: "delete", defaults: { id: nil } match "contacts", to: "domains/contacts#destroy", via: "delete", defaults: { id: nil } collection do From 99a1f1f489f6a8f8e720f4a7b0f391b59e8478b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 22 Jan 2021 14:02:15 +0200 Subject: [PATCH 28/80] REPP: Read/Ack poll messages --- app/controllers/repp/v1/domains_controller.rb | 4 +- .../v1/registrar/notifications_controller.rb | 48 +++++++++++++++++++ config/routes.rb | 1 + 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 app/controllers/repp/v1/registrar/notifications_controller.rb diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index a63f40402..3d0ba8c56 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -35,7 +35,7 @@ module Repp param :ipv6, Array, desc: 'Array of IPv4 addresses' end param :admin_domain_contacts_attributes, Array, required: false, desc: 'Admin domain contacts codes' - param :admin_domain_contacts_attributes, Array, required: false, desc: 'Tech domain contacts codes' + param :tech_domain_contacts_attributes, Array, required: false, desc: 'Tech domain contacts codes' param :dnskeys_attributes, Array, required: false, desc: 'DNSSEC keys for domain' do param :flags, String, required: true, desc: 'Flag of DNSSEC key' param :protocol, String, required: true, desc: 'Protocol of DNSSEC key' @@ -143,6 +143,8 @@ module Repp end def forward_registrar_id + return unless params[:domain] + params[:domain][:registrar_id] = current_user.registrar.id end diff --git a/app/controllers/repp/v1/registrar/notifications_controller.rb b/app/controllers/repp/v1/registrar/notifications_controller.rb new file mode 100644 index 000000000..0f6808710 --- /dev/null +++ b/app/controllers/repp/v1/registrar/notifications_controller.rb @@ -0,0 +1,48 @@ +module Repp + module V1 + module Registrar + class NotificationsController < BaseController + before_action :set_notification, only: [:update] + + api :GET, '/repp/v1/registrar/notifications' + desc 'Get the latest unread poll message' + def index + @notification = current_user.unread_notifications.order('created_at DESC').take + render_success(data: nil) and return unless @notification + + data = @notification.as_json(only: [:id, :text, :attached_obj_id, + :attached_obj_type]) + + render_success(data: data) + end + + api :GET, '/repp/v1/registrar/notifications/:notification_id' + desc 'Get a specific poll message' + def show + @notification = current_user.registrar.notifications.find(params[:id]) + data = @notification.as_json(only: [:id, :text, :attached_obj_id, + :attached_obj_type]) + + render_success(data: data) + end + + api :PUT, '/repp/v1/registrar/notifications' + desc 'Mark poll message as read' + param :notification, Hash, required: true do + param :read, [true], required: true, desc: "Set as true to mark as read" + end + def update + handle_errors(@notification) and return unless @notification.mark_as_read + + render_success(data: { notification_id: @notification.id, read: true }) + end + + private + + def set_notification + @notification = current_user.unread_notifications.find(params[:id]) + end + end + end + end +end diff --git a/config/routes.rb b/config/routes.rb index 0bd0da82e..10a6f2b6e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -53,6 +53,7 @@ Rails.application.routes.draw do resources :auctions, only: %i[index] resources :retained_domains, only: %i[index] namespace :registrar do + resources :notifications, only: [:index, :show, :update] resources :nameservers do collection do put '/', to: 'nameservers#update' From cdf286643430b3ad01876b8884066eb4c6aa1494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 26 Jan 2021 15:47:53 +0200 Subject: [PATCH 29/80] REPP: Domain Delete endpoint, port EPP Delete to Actions --- app/controllers/epp/domains_controller.rb | 29 ++++------ app/controllers/repp/v1/domains_controller.rb | 22 +++++-- app/models/actions/domain_delete.rb | 57 +++++++++++++++++++ lib/deserializers/xml/domain_delete.rb | 20 +++++++ 4 files changed, 106 insertions(+), 22 deletions(-) create mode 100644 app/models/actions/domain_delete.rb create mode 100644 lib/deserializers/xml/domain_delete.rb diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index 546cc131b..656e51874 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -1,3 +1,4 @@ +require 'deserializers/xml/domain_delete' module Epp class DomainsController < BaseController before_action :find_domain, only: %i[info renew update transfer delete] @@ -43,28 +44,22 @@ module Epp update_params = ::Deserializers::Xml::DomainUpdate.new(params[:parsed_frame], registrar_id).call action = Actions::DomainUpdate.new(@domain, update_params, false) - if action.call - pending = @domain.epp_pending_update.present? - render_epp_response("/epp/domains/success#{'_pending' if pending}") - else - handle_errors(@domain) - end + (handle_errors(@domain) and return) unless action.call + + pending = @domain.epp_pending_update.present? + render_epp_response("/epp/domains/success#{'_pending' if pending}") end def delete - authorize! :delete, @domain, @password + authorize!(:delete, @domain, @password) + frame = params[:parsed_frame] + delete_params = ::Deserializers::Xml::DomainDelete.new(frame).call + action = Actions::DomainDelete.new(@domain, delete_params, current_user.registrar) - (handle_errors(@domain) && return) unless @domain.can_be_deleted? + (handle_errors(@domain) and return) unless action.call - if @domain.epp_destroy(params[:parsed_frame], current_user.id) - if @domain.epp_pending_delete.present? - render_epp_response '/epp/domains/success_pending' - else - render_epp_response '/epp/domains/success' - end - else - handle_errors(@domain) - end + pending = @domain.epp_pending_delete.present? + render_epp_response("/epp/domains/success#{'_pending' if pending}") end def check diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 3d0ba8c56..6115d972b 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -2,8 +2,8 @@ require 'serializers/registrant_api/domain' module Repp module V1 class DomainsController < BaseController - before_action :set_authorized_domain, only: %i[transfer_info] - before_action :forward_registrar_id, only: %i[create] + before_action :set_authorized_domain, only: %i[transfer_info destroy] + before_action :forward_registrar_id, only: %i[create destroy] before_action :set_domain, only: %i[show update] api :GET, '/repp/v1/domains' @@ -112,6 +112,20 @@ module Repp render_success(data: { success: @successful, failed: @errors }) end + api :DELETE, '/repp/v1/domains/:domain_name' + desc 'Delete specific domain' + param :delete, Hash, required: true, desc: 'Object holding verified key' do + param :verified, [true, false], required: true, desc: 'Whether to ask registrant verification or not' + end + def destroy + action = Actions::DomainDelete.new(@domain, params, current_user.registrar) + handle_errors(@domain) and return unless action.call + + render_success(data: { domain: { name: @domain.name }}) + end + + private + def initiate_transfer(transfer) domain = Epp::Domain.find_or_initialize_by(name: transfer[:domain_name]) action = Actions::DomainTransfer.new(domain, transfer[:transfer_code], @@ -125,8 +139,6 @@ module Repp end end - private - def transfer_params params.require(:data).require(:domain_transfers).each do |t| t.require(:domain_name) @@ -156,7 +168,7 @@ module Repp @epp_errors ||= [] h = {} h[transfer_info_params[:id].match?(/\A[0-9]+\z/) ? :id : :name] = transfer_info_params[:id] - @domain = Domain.find_by!(h) + @domain = Epp::Domain.find_by!(h) validate_registrar_authorization end diff --git a/app/models/actions/domain_delete.rb b/app/models/actions/domain_delete.rb new file mode 100644 index 000000000..f3197c452 --- /dev/null +++ b/app/models/actions/domain_delete.rb @@ -0,0 +1,57 @@ +module Actions + class DomainDelete + attr_reader :domain + attr_reader :params + attr_reader :user + + def initialize(domain, params, user) + @domain = domain + @params = params + @user = user + end + + def call + return false unless @domain.can_be_deleted? + + verify_not_discarded + maybe_attach_legal_doc + + return false if domain.errors.any? + return false if domain.errors[:epp_errors].any? + + destroy + end + + def maybe_attach_legal_doc + Actions::BaseAction.attach_legal_doc_to_new(domain, params[:legal_document], domain: true) + end + + def verify_not_discarded + return unless domain.discarded? + + domain.add_epp_error('2304', nil, nil, 'Object status prohibits operation') + end + + def verify? + return false unless Setting.request_confirmation_on_domain_deletion_enabled + return false if params[:delete][:verified] == true + + true + end + + def destroy + if verify? + domain.registrant_verification_asked!(params, user.id) + domain.pending_delete! + domain.manage_automatic_statuses + else + domain.set_pending_delete! + end + + return false if domain.errors.any? + return false if domain.errors[:epp_errors].any? + + true + end + end +end diff --git a/lib/deserializers/xml/domain_delete.rb b/lib/deserializers/xml/domain_delete.rb new file mode 100644 index 000000000..b682c9b5b --- /dev/null +++ b/lib/deserializers/xml/domain_delete.rb @@ -0,0 +1,20 @@ +module Deserializers + module Xml + class DomainDelete + attr_reader :frame + + def initialize(frame) + @frame = frame + end + + def call + obj = {} + obj[:name] = frame.css('name')&.text + verify = frame.css('delete').children.css('delete').attr('verified').to_s.downcase == 'yes' + obj[:delete] = { verified: verify } + + obj + end + end + end +end From 9a7827107f944e10fa1e49de5fa65cc5e3d1bd92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 26 Jan 2021 17:38:13 +0200 Subject: [PATCH 30/80] REPP: Create domain serializer --- lib/serializers/repp/domain.rb | 37 ++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 lib/serializers/repp/domain.rb diff --git a/lib/serializers/repp/domain.rb b/lib/serializers/repp/domain.rb new file mode 100644 index 000000000..a623ab184 --- /dev/null +++ b/lib/serializers/repp/domain.rb @@ -0,0 +1,37 @@ +module Serializers + module Repp + class Domain + attr_reader :domain + + def initialize(domain) + @domain = domain + end + + def to_json(obj = domain) + json = { + name: obj.name, registrant: obj.registrant.code, created_at: obj.created_at, + updated_at: obj.updated_at, expire_time: obj.expire_time, outzone_at: obj.outzone_at, + delete_date: obj.delete_date, force_delete_date: obj.force_delete_date, + authorization_code: obj.auth_info, contacts: contacts, nameservers: nameservers, + dnssec_keys: dnssec_keys, statuses: obj.statuses, + } + + json + end + + def contacts + domain.domain_contacts.map { |c| { code: c.contact_code_cache, type: c.type } } + end + + def nameservers + domain.nameservers.map { |ns| { hostname: ns.hostname, ipv4: ns.ipv4, ipv6: ns.ipv6 } } + end + + def dnssec_keys + domain.dnskeys.map do |nssec| + { flags: nsec.flags, protocol: nssec.protocol, alg: nssec.alg, public_key: nssec.public_key } + end + end + end + end +end From 988af6c91cadc99c9b1bdc0b8cc8c413036508da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 27 Jan 2021 11:30:44 +0200 Subject: [PATCH 31/80] Fix domain renew porting to actions --- app/controllers/epp/domains_controller.rb | 7 ++++++- app/interactions/domains/bulk_renew/single_domain_renew.rb | 1 + app/models/actions/domain_renew.rb | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index 656e51874..80b7d8843 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -72,7 +72,7 @@ module Epp def renew authorize! :renew, @domain - @domain.validate_exp_dates(params[:parsed_frame].css('curExpDate').text) + return handle_errors(@domain) if invalid_expiry_date? registrar_id = current_user.registrar.id renew_params = ::Deserializers::Xml::Domain.new(params[:parsed_frame], @@ -228,6 +228,11 @@ module Epp statuses == [::DomainStatus::CLIENT_HOLD] end + def invalid_expiry_date? + @domain.validate_exp_dates(params[:parsed_frame].css('curExpDate').text) + @domain.errors[:epp_errors].any? + end + def balance_ok?(operation, period = nil, unit = nil) @domain_pricelist = @domain.pricelist(operation, period.try(:to_i), unit) if @domain_pricelist.try(:price) # checking if price list is not found diff --git a/app/interactions/domains/bulk_renew/single_domain_renew.rb b/app/interactions/domains/bulk_renew/single_domain_renew.rb index 66c6244b3..bcfc5b451 100644 --- a/app/interactions/domains/bulk_renew/single_domain_renew.rb +++ b/app/interactions/domains/bulk_renew/single_domain_renew.rb @@ -9,6 +9,7 @@ module Domains def execute in_transaction_with_retries do + check_balance success = domain.renew(domain.valid_to, period, unit) if success check_balance diff --git a/app/models/actions/domain_renew.rb b/app/models/actions/domain_renew.rb index 3e9740335..1069e4a66 100644 --- a/app/models/actions/domain_renew.rb +++ b/app/models/actions/domain_renew.rb @@ -15,6 +15,11 @@ module Actions end def renew + if !domain.renewable? || domain.invalid? + domain.add_renew_epp_errors + return + end + task = Domains::BulkRenew::SingleDomainRenew.run(domain: domain, period: params[:period], unit: params[:period_unit], From 57df268d916308202068ee757e31c87af6ac3877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 27 Jan 2021 12:33:46 +0200 Subject: [PATCH 32/80] REPP: Create domain statuses endpoints --- .../repp/v1/domains/statuses_controller.rb | 74 +++++++++++++++++++ config/routes.rb | 1 + 2 files changed, 75 insertions(+) create mode 100644 app/controllers/repp/v1/domains/statuses_controller.rb diff --git a/app/controllers/repp/v1/domains/statuses_controller.rb b/app/controllers/repp/v1/domains/statuses_controller.rb new file mode 100644 index 000000000..72bd7e7f6 --- /dev/null +++ b/app/controllers/repp/v1/domains/statuses_controller.rb @@ -0,0 +1,74 @@ +module Repp + module V1 + module Domains + class StatusesController < BaseController + before_action :set_domain, only: %i[update destroy] + before_action :verify_status + before_action :verify_status_removal, only: [:destroy] + before_action :verify_status_create, only: [:update] + + api :DELETE, '/repp/v1/domains/:domain_name/statuses/:status' + desc 'Remove status from specific domain' + param :domain_name, String, required: true, desc: 'Domain name' + param :status, String, required: true, desc: 'Status to be removed' + def destroy + @domain.statuses = @domain.statuses.delete(params[:id]) + if @domain.save + render_success + else + handle_errors(@domain) + end + end + + api :PUT, '/repp/v1/domains/:domain_name/statuses/:status' + desc 'Add status to specific domain' + param :domain_name, String, required: true, desc: 'Domain name' + param :status, String, required: true, desc: 'Status to be added' + def update + @domain.statuses = @domain.statuses << params[:id] + handle_errors(@domain) and return unless @domain.save + + render_success(data: { domain: @domain.name, status: params[:id] }) + end + + private + + def set_domain + registrar = current_user.registrar + @domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id]) + @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id]) + + return @domain if @domain + + raise(ActiveRecord::RecordNotFound) + end + + def verify_status + allowed_statuses = [DomainStatus::CLIENT_HOLD].freeze + stat = params[:id] + + return if allowed_statuses.include?(stat) + + @domain.add_epp_error('2306', nil, nil, "#{I18n.t(:client_side_status_editing_error)}: status #{stat}") + handle_errors(@domain) + end + + def verify_status_removal + stat = params[:id] + return if @domain.statuses.include?(stat) + + @domain.add_epp_error('2306', nil, nil, "#{I18n.t(:client_side_status_editing_error)}: status #{stat}") + handle_errors(@domain) + end + + def verify_status_create + stat = params[:id] + return unless @domain.statuses.include?(stat) + + @domain.add_epp_error('2306', nil, nil, "#{I18n.t(:client_side_status_editing_error)}: status #{stat}") + handle_errors(@domain) + end + end + end + end +end diff --git a/config/routes.rb b/config/routes.rb index 10a6f2b6e..85e2bbccb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -66,6 +66,7 @@ Rails.application.routes.draw do resources :contacts, only: %i[index create], constraints: { id: /.*/ }, controller: 'domains/contacts' resources :renew, only: %i[create], constraints: { id: /.*/ }, controller: 'domains/renews' resources :transfer, only: %i[create], constraints: { id: /.*/ }, controller: 'domains/transfers' + resources :statuses, only: %i[update destroy], constraints: { id: /.*/ }, controller: 'domains/statuses' match "dnssec", to: "domains/dnssec#destroy", via: "delete", defaults: { id: nil } match "contacts", to: "domains/contacts#destroy", via: "delete", defaults: { id: nil } collection do From e55fc833e7175fb0ba84ba4384b786fb60d004f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 27 Jan 2021 13:01:59 +0200 Subject: [PATCH 33/80] REPP: Serialize domains --- app/controllers/repp/v1/domains_controller.rb | 8 ++++++-- lib/serializers/repp/domain.rb | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 6115d972b..703d3efd2 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -1,4 +1,4 @@ -require 'serializers/registrant_api/domain' +require 'serializers/repp/domain' module Repp module V1 class DomainsController < BaseController @@ -13,13 +13,17 @@ module Repp domains = records.limit(limit).offset(offset) domains = domains.pluck(:name) unless index_params[:details] == 'true' + if index_params[:details] == 'true' + domains = domains.map { |d| Serializers::Repp::Domain.new(d).to_json } + end + render_success(data: { domains: domains, total_number_of_records: records.count }) end api :GET, '/repp/v1/domains/:domain_name' desc 'Get a specific domain' def show - render_success(data: { domain: Serializers::RegistrantApi::Domain.new(@domain).to_json }) + render_success(data: { domain: Serializers::Repp::Domain.new(@domain).to_json }) end api :POST, '/repp/v1/domains' diff --git a/lib/serializers/repp/domain.rb b/lib/serializers/repp/domain.rb index a623ab184..b8afa6693 100644 --- a/lib/serializers/repp/domain.rb +++ b/lib/serializers/repp/domain.rb @@ -29,7 +29,8 @@ module Serializers def dnssec_keys domain.dnskeys.map do |nssec| - { flags: nsec.flags, protocol: nssec.protocol, alg: nssec.alg, public_key: nssec.public_key } + { flags: nssec.flags, protocol: nssec.protocol, alg: nssec.alg, + public_key: nssec.public_key } end end end From 2ca9697b4659a5e238c841f03b39c1fbafd3c605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 27 Jan 2021 13:31:30 +0200 Subject: [PATCH 34/80] Remove redundant methods --- app/controllers/repp/v1/base_controller.rb | 10 ++++++++++ app/controllers/repp/v1/domains/contacts_controller.rb | 8 -------- app/controllers/repp/v1/domains/dnssec_controller.rb | 8 -------- .../repp/v1/domains/nameservers_controller.rb | 8 -------- app/controllers/repp/v1/domains/renews_controller.rb | 10 ---------- app/controllers/repp/v1/domains/statuses_controller.rb | 10 ---------- app/controllers/repp/v1/domains_controller.rb | 6 +++++- 7 files changed, 15 insertions(+), 45 deletions(-) diff --git a/app/controllers/repp/v1/base_controller.rb b/app/controllers/repp/v1/base_controller.rb index 053e1ac42..a4e613786 100644 --- a/app/controllers/repp/v1/base_controller.rb +++ b/app/controllers/repp/v1/base_controller.rb @@ -25,6 +25,16 @@ module Repp private + def set_domain + registrar = current_user.registrar + @domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id]) + @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id]) + + return @domain if @domain + + raise ActiveRecord::RecordNotFound + end + def set_paper_trail_whodunnit ::PaperTrail.request.whodunnit = current_user end diff --git a/app/controllers/repp/v1/domains/contacts_controller.rb b/app/controllers/repp/v1/domains/contacts_controller.rb index 631916a67..1705e7cc0 100644 --- a/app/controllers/repp/v1/domains/contacts_controller.rb +++ b/app/controllers/repp/v1/domains/contacts_controller.rb @@ -79,14 +79,6 @@ module Repp private - def set_domain - registrar = current_user.registrar - @domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id]) - @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id]) - - @domain - end - def contact_create_params params.permit! end diff --git a/app/controllers/repp/v1/domains/dnssec_controller.rb b/app/controllers/repp/v1/domains/dnssec_controller.rb index 5d352dc3e..717210091 100644 --- a/app/controllers/repp/v1/domains/dnssec_controller.rb +++ b/app/controllers/repp/v1/domains/dnssec_controller.rb @@ -53,14 +53,6 @@ module Repp private - def set_domain - registrar = current_user.registrar - @domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id]) - @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id]) - - @domain - end - def dnssec_params params.permit! end diff --git a/app/controllers/repp/v1/domains/nameservers_controller.rb b/app/controllers/repp/v1/domains/nameservers_controller.rb index e307bb1d6..ce4227bab 100644 --- a/app/controllers/repp/v1/domains/nameservers_controller.rb +++ b/app/controllers/repp/v1/domains/nameservers_controller.rb @@ -40,14 +40,6 @@ module Repp private - def set_domain - registrar = current_user.registrar - @domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id]) - @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id]) - - @domain - end - def set_nameserver @nameserver = @domain.nameservers.find_by!(hostname: params[:id]) end diff --git a/app/controllers/repp/v1/domains/renews_controller.rb b/app/controllers/repp/v1/domains/renews_controller.rb index e77c2e2d0..74a9ad2e2 100644 --- a/app/controllers/repp/v1/domains/renews_controller.rb +++ b/app/controllers/repp/v1/domains/renews_controller.rb @@ -35,16 +35,6 @@ module Repp private - def set_domain - registrar = current_user.registrar - @domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id]) - @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id]) - - return @domain if @domain - - raise ActiveRecord::RecordNotFound - end - def renew_params params.permit! end diff --git a/app/controllers/repp/v1/domains/statuses_controller.rb b/app/controllers/repp/v1/domains/statuses_controller.rb index 72bd7e7f6..413544232 100644 --- a/app/controllers/repp/v1/domains/statuses_controller.rb +++ b/app/controllers/repp/v1/domains/statuses_controller.rb @@ -33,16 +33,6 @@ module Repp private - def set_domain - registrar = current_user.registrar - @domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id]) - @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id]) - - return @domain if @domain - - raise(ActiveRecord::RecordNotFound) - end - def verify_status allowed_statuses = [DomainStatus::CLIENT_HOLD].freeze stat = params[:id] diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 703d3efd2..db1ea465d 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -165,7 +165,11 @@ module Repp end def set_domain - @domain = Epp::Domain.find_by!(registrar: current_user.registrar, name: params[:id]) + registrar = current_user.registrar + @domain = Epp::Domain.find_by(registrar: registrar, name: params[:id]) + @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:id]) + + @domain end def set_authorized_domain From d1cd0867c84450342933d58e55176bcaa754847a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 27 Jan 2021 13:50:27 +0200 Subject: [PATCH 35/80] Fix some CC issues --- Gemfile | 4 +-- .../repp/v1/accounts_controller.rb | 1 - app/controllers/repp/v1/base_controller.rb | 3 +- .../repp/v1/domains/contacts_controller.rb | 21 ++++++------- .../repp/v1/domains/dnssec_controller.rb | 19 ++++++------ .../repp/v1/domains/statuses_controller.rb | 25 +++++++--------- .../repp/v1/domains/transfers_controller.rb | 3 +- app/controllers/repp/v1/domains_controller.rb | 30 +++++++++++-------- .../v1/registrar/notifications_controller.rb | 15 ++++++---- .../domains/check_balance/single_domain.rb | 2 +- app/models/actions/domain_create.rb | 4 ++- app/models/actions/domain_renew.rb | 6 ++-- lib/serializers/repp/domain.rb | 2 +- 13 files changed, 72 insertions(+), 63 deletions(-) diff --git a/Gemfile b/Gemfile index 531cad50a..b248030e9 100644 --- a/Gemfile +++ b/Gemfile @@ -2,6 +2,7 @@ source 'https://rubygems.org' # core gem 'active_interaction', '~> 3.8' +gem 'apipie-rails', '~> 0.5.18' gem 'bootsnap', '>= 1.1.0', require: false gem 'iso8601', '0.12.1' # for dates and times gem 'rails', '~> 6.0' @@ -78,7 +79,6 @@ gem 'wkhtmltopdf-binary', '~> 0.12.5.1' gem 'directo', github: 'internetee/directo', branch: 'master' - group :development, :test do gem 'pry', '0.10.1' gem 'puma' @@ -92,5 +92,3 @@ group :test do gem 'webdrivers' gem 'webmock' end - -gem "apipie-rails", "~> 0.5.18" diff --git a/app/controllers/repp/v1/accounts_controller.rb b/app/controllers/repp/v1/accounts_controller.rb index 00f70ea63..7397b274d 100644 --- a/app/controllers/repp/v1/accounts_controller.rb +++ b/app/controllers/repp/v1/accounts_controller.rb @@ -1,7 +1,6 @@ module Repp module V1 class AccountsController < BaseController - api :GET, '/repp/v1/accounts/balance' desc "Get account's balance" def balance diff --git a/app/controllers/repp/v1/base_controller.rb b/app/controllers/repp/v1/base_controller.rb index a4e613786..339d03311 100644 --- a/app/controllers/repp/v1/base_controller.rb +++ b/app/controllers/repp/v1/base_controller.rb @@ -9,7 +9,8 @@ module Repp before_action :set_paper_trail_whodunnit - rescue_from ActionController::ParameterMissing, Apipie::ParamInvalid, Apipie::ParamMissing do |exception| + rescue_from ActionController::ParameterMissing, Apipie::ParamInvalid, + Apipie::ParamMissing do |exception| render json: { code: 2003, message: exception }, status: :bad_request end diff --git a/app/controllers/repp/v1/domains/contacts_controller.rb b/app/controllers/repp/v1/domains/contacts_controller.rb index 1705e7cc0..86cbf0acf 100644 --- a/app/controllers/repp/v1/domains/contacts_controller.rb +++ b/app/controllers/repp/v1/domains/contacts_controller.rb @@ -6,6 +6,13 @@ module Repp before_action :set_new_contact, only: [:update] before_action :set_domain, only: %i[index create destroy] + def_param_group :contacts_apidoc do + param :contacts, Array, required: true, desc: 'Array of new linked contacts' do + param :code, String, required: true, desc: 'Contact code' + param :type, String, required: true, desc: 'Role of contact (admin/tech)' + end + end + api :GET, '/repp/v1/domains/:domain_name/contacts' desc "View domain's admin and tech contacts" def index @@ -17,11 +24,8 @@ module Repp end api :POST, '/repp/v1/domains/:domain_name/contacts' - desc "Link new contact(s) to domain" - param :contacts, Array, required: true, desc: 'Array of new linked contacts' do - param :code, String, required: true, desc: 'Contact code' - param :type, String, required: true, desc: 'Role of contact (admin/tech)' - end + desc 'Link new contact(s) to domain' + param_group :contacts_apidoc def create contact_create_params[:contacts].each { |c| c[:action] = 'add' } action = Actions::DomainUpdate.new(@domain, contact_create_params, current_user) @@ -35,11 +39,8 @@ module Repp end api :DELETE, '/repp/v1/domains/:domain_name/contacts' - desc "Remove contact(s) from domain" - param :contacts, Array, required: true, desc: 'Array of new linked contacts' do - param :code, String, required: true, desc: 'Contact code' - param :type, String, required: true, desc: 'Role of contact (admin/tech)' - end + desc 'Remove contact(s) from domain' + param_group :contacts_apidoc def destroy contact_create_params[:contacts].each { |c| c[:action] = 'rem' } action = Actions::DomainUpdate.new(@domain, contact_create_params, current_user) diff --git a/app/controllers/repp/v1/domains/dnssec_controller.rb b/app/controllers/repp/v1/domains/dnssec_controller.rb index 717210091..ec3a3bd7f 100644 --- a/app/controllers/repp/v1/domains/dnssec_controller.rb +++ b/app/controllers/repp/v1/domains/dnssec_controller.rb @@ -4,6 +4,13 @@ module Repp class DnssecController < BaseController before_action :set_domain, only: %i[index create destroy] + def_param_group :dns_keys_apidoc do + param :flags, String, required: true, desc: '256 (KSK) or 257 (ZSK)' + param :protocol, String, required: true, desc: 'Key protocol (3)' + param :alg, String, required: true, desc: 'DNSSEC key algorithm (3,5,6,7,8,10,13,14)' + param :public_key, String, required: true, desc: 'DNSSEC public key' + end + api :GET, '/repp/v1/domains/:domain_name/dnssec' desc "View specific domain's DNSSEC keys" def index @@ -15,10 +22,7 @@ module Repp api :POST, '/repp/v1/domains/:domain_name/dnssec' desc 'Create a new DNSSEC key(s) for domain' param :dns_keys, Array, required: true, desc: 'Array of new DNSSEC keys' do - param :flags, String, required: true, desc: '256 (KSK) or 257 (ZSK)' - param :protocol, String, required: true, desc: 'Key protocol (3)' - param :alg, String, required: true, desc: 'DNSSEC key algorithm (3,5,6,7,8,10,13,14)' - param :public_key, String, required: true, desc: 'DNSSEC public key' + param_group :dns_keys_apidoc, DnssecController end def create dnssec_params[:dnssec][:dns_keys].each { |n| n[:action] = 'add' } @@ -33,11 +37,8 @@ module Repp end api :DELETE, 'repp/v1/domains/:domain_name/dnssec' - param :dns_keys, Array, required: true, desc: 'Array of removable DNSSEC keys' do - param :flags, String, required: true, desc: '256 (KSK) or 257 (ZSK)' - param :protocol, String, required: true, desc: 'Key protocol (3)' - param :alg, String, required: true, desc: 'DNSSEC key algorithm (3,5,6,7,8,10,13,14)' - param :public_key, String, required: true, desc: 'DNSSEC public key' + param :dns_keys, Array, required: true, desc: 'Array of new DNSSEC keys' do + param_group :dns_keys_apidoc, DnssecController end def destroy dnssec_params[:dnssec][:dns_keys].each { |n| n[:action] = 'rem' } diff --git a/app/controllers/repp/v1/domains/statuses_controller.rb b/app/controllers/repp/v1/domains/statuses_controller.rb index 413544232..1b1d47477 100644 --- a/app/controllers/repp/v1/domains/statuses_controller.rb +++ b/app/controllers/repp/v1/domains/statuses_controller.rb @@ -4,14 +4,14 @@ module Repp class StatusesController < BaseController before_action :set_domain, only: %i[update destroy] before_action :verify_status - before_action :verify_status_removal, only: [:destroy] - before_action :verify_status_create, only: [:update] api :DELETE, '/repp/v1/domains/:domain_name/statuses/:status' desc 'Remove status from specific domain' param :domain_name, String, required: true, desc: 'Domain name' param :status, String, required: true, desc: 'Status to be removed' def destroy + return editing_failed unless @domain.statuses.include?(params[:id]) + @domain.statuses = @domain.statuses.delete(params[:id]) if @domain.save render_success @@ -25,8 +25,12 @@ module Repp param :domain_name, String, required: true, desc: 'Domain name' param :status, String, required: true, desc: 'Status to be added' def update + return editing_failed if @domain.statuses.include?(params[:id]) + @domain.statuses = @domain.statuses << params[:id] + # rubocop:disable Style/AndOr handle_errors(@domain) and return unless @domain.save + # rubocop:enable Style/AndOr render_success(data: { domain: @domain.name, status: params[:id] }) end @@ -39,23 +43,16 @@ module Repp return if allowed_statuses.include?(stat) - @domain.add_epp_error('2306', nil, nil, "#{I18n.t(:client_side_status_editing_error)}: status #{stat}") + @domain.add_epp_error('2306', nil, nil, + "#{I18n.t(:client_side_status_editing_error)}: status #{stat}") handle_errors(@domain) end - def verify_status_removal + def editing_failed stat = params[:id] - return if @domain.statuses.include?(stat) - @domain.add_epp_error('2306', nil, nil, "#{I18n.t(:client_side_status_editing_error)}: status #{stat}") - handle_errors(@domain) - end - - def verify_status_create - stat = params[:id] - return unless @domain.statuses.include?(stat) - - @domain.add_epp_error('2306', nil, nil, "#{I18n.t(:client_side_status_editing_error)}: status #{stat}") + @domain.add_epp_error('2306', nil, nil, + "#{I18n.t(:client_side_status_editing_error)}: status #{stat}") handle_errors(@domain) end end diff --git a/app/controllers/repp/v1/domains/transfers_controller.rb b/app/controllers/repp/v1/domains/transfers_controller.rb index be1f754c2..2594205d6 100644 --- a/app/controllers/repp/v1/domains/transfers_controller.rb +++ b/app/controllers/repp/v1/domains/transfers_controller.rb @@ -24,8 +24,9 @@ module Repp private def set_domain + domain_id = transfer_params[:domain_id] h = {} - h[transfer_params[:domain_id].match?(/\A[0-9]+\z/) ? :id : :name] = transfer_params[:domain_id] + h[domain_id.match?(/\A[0-9]+\z/) ? :id : :name] = domain_id @domain = Epp::Domain.find_by!(h) end diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index db1ea465d..8e77cd219 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -38,13 +38,12 @@ module Repp param :ipv4, Array, desc: 'Array of IPv4 addresses' param :ipv6, Array, desc: 'Array of IPv4 addresses' end - param :admin_domain_contacts_attributes, Array, required: false, desc: 'Admin domain contacts codes' - param :tech_domain_contacts_attributes, Array, required: false, desc: 'Tech domain contacts codes' + param :admin_domain_contacts_attributes, Array, required: false, + desc: 'Admin domain contacts codes' + param :tech_domain_contacts_attributes, Array, required: false, + desc: 'Tech domain contacts codes' param :dnskeys_attributes, Array, required: false, desc: 'DNSSEC keys for domain' do - param :flags, String, required: true, desc: 'Flag of DNSSEC key' - param :protocol, String, required: true, desc: 'Protocol of DNSSEC key' - param :alg, String, required: true, desc: 'Algorithm of DNSSEC key' - param :public_key, String, required: true, desc: 'Public key of DNSSEC key' + param_group :dns_keys_apidoc, Repp::V1::Domains::DnssecController end end returns code: 200, desc: 'Successful domain registration response' do @@ -61,7 +60,9 @@ module Repp @domain = Epp::Domain.new action = Actions::DomainCreate.new(@domain, domain_create_params) + # rubocop:disable Style/AndOr handle_errors(@domain) and return unless action.call + # rubocop:enable Style/AndOr render_success(data: { domain: { name: @domain.name } }) end @@ -72,7 +73,8 @@ module Repp param :domain, Hash, required: true, desc: 'Changes of domain object' do param :registrant, Hash, required: false, desc: 'New registrant object' do param :code, String, required: true, desc: 'New registrant contact code' - param :verified, [true, false], required: false, desc: 'Registrant change is already verified' + param :verified, [true, false], required: false, + desc: 'Registrant change is already verified' end param :auth_info, String, required: false, desc: 'New authorization code' end @@ -119,13 +121,17 @@ module Repp api :DELETE, '/repp/v1/domains/:domain_name' desc 'Delete specific domain' param :delete, Hash, required: true, desc: 'Object holding verified key' do - param :verified, [true, false], required: true, desc: 'Whether to ask registrant verification or not' + param :verified, [true, false], required: true, + desc: 'Whether to ask registrant verification or not' end def destroy action = Actions::DomainDelete.new(@domain, params, current_user.registrar) - handle_errors(@domain) and return unless action.call - render_success(data: { domain: { name: @domain.name }}) + # rubocop:disable Style/AndOr + handle_errors(@domain) and return unless action.call + # rubocop:enable Style/AndOr + + render_success(data: { domain: { name: @domain.name } }) end private @@ -202,8 +208,8 @@ module Repp end def domain_create_params - params.require(:domain).require([:name, :registrant_id, :period, :period_unit]) - params.require(:domain).permit(:name, :registrant_id, :period, :period_unit, :registrar_id) + params.require(:domain).require(%i[name registrant_id period period_unit]) + params.require(:domain).permit(%i[name registrant_id period period_unit registrar_id]) end end end diff --git a/app/controllers/repp/v1/registrar/notifications_controller.rb b/app/controllers/repp/v1/registrar/notifications_controller.rb index 0f6808710..2c5ced56b 100644 --- a/app/controllers/repp/v1/registrar/notifications_controller.rb +++ b/app/controllers/repp/v1/registrar/notifications_controller.rb @@ -8,10 +8,12 @@ module Repp desc 'Get the latest unread poll message' def index @notification = current_user.unread_notifications.order('created_at DESC').take - render_success(data: nil) and return unless @notification - data = @notification.as_json(only: [:id, :text, :attached_obj_id, - :attached_obj_type]) + # rubocop:disable Style/AndOr + render_success(data: nil) and return unless @notification + # rubocop:enable Style/AndOr + + data = @notification.as_json(only: %i[id text attached_obj_id attached_obj_type]) render_success(data: data) end @@ -20,8 +22,7 @@ module Repp desc 'Get a specific poll message' def show @notification = current_user.registrar.notifications.find(params[:id]) - data = @notification.as_json(only: [:id, :text, :attached_obj_id, - :attached_obj_type]) + data = @notification.as_json(only: %i[id text attached_obj_id attached_obj_type]) render_success(data: data) end @@ -29,10 +30,12 @@ module Repp api :PUT, '/repp/v1/registrar/notifications' desc 'Mark poll message as read' param :notification, Hash, required: true do - param :read, [true], required: true, desc: "Set as true to mark as read" + param :read, [true], required: true, desc: 'Set as true to mark as read' end def update + # rubocop:disable Style/AndOr handle_errors(@notification) and return unless @notification.mark_as_read + # rubocop:enable Style/AndOr render_success(data: { notification_id: @notification.id, read: true }) end diff --git a/app/interactions/domains/check_balance/single_domain.rb b/app/interactions/domains/check_balance/single_domain.rb index de8f24d18..607913e92 100644 --- a/app/interactions/domains/check_balance/single_domain.rb +++ b/app/interactions/domains/check_balance/single_domain.rb @@ -13,7 +13,7 @@ module Domains domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain, - domain: domain.name)) + domain: domain.name)) false end diff --git a/app/models/actions/domain_create.rb b/app/models/actions/domain_create.rb index f028ec4ef..274a070fb 100644 --- a/app/models/actions/domain_create.rb +++ b/app/models/actions/domain_create.rb @@ -82,7 +82,9 @@ module Actions end def assign_nameservers - domain.nameservers_attributes = params[:nameservers_attributes] if params[:nameservers_attributes] + return unless params[:nameservers_attributes] + + domain.nameservers_attributes = params[:nameservers_attributes] end def assign_contact(contact_code, admin: true) diff --git a/app/models/actions/domain_renew.rb b/app/models/actions/domain_renew.rb index 1069e4a66..ba1ac8fb3 100644 --- a/app/models/actions/domain_renew.rb +++ b/app/models/actions/domain_renew.rb @@ -21,9 +21,9 @@ module Actions end task = Domains::BulkRenew::SingleDomainRenew.run(domain: domain, - period: params[:period], - unit: params[:period_unit], - registrar: user) + period: params[:period], + unit: params[:period_unit], + registrar: user) task.valid? end diff --git a/lib/serializers/repp/domain.rb b/lib/serializers/repp/domain.rb index b8afa6693..5821e1568 100644 --- a/lib/serializers/repp/domain.rb +++ b/lib/serializers/repp/domain.rb @@ -13,7 +13,7 @@ module Serializers updated_at: obj.updated_at, expire_time: obj.expire_time, outzone_at: obj.outzone_at, delete_date: obj.delete_date, force_delete_date: obj.force_delete_date, authorization_code: obj.auth_info, contacts: contacts, nameservers: nameservers, - dnssec_keys: dnssec_keys, statuses: obj.statuses, + dnssec_keys: dnssec_keys, statuses: obj.statuses } json From 8c01385be05547f3be322c447e9285f113cfcc32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 27 Jan 2021 16:13:10 +0200 Subject: [PATCH 36/80] REPP: Combine create/delete actions for domain contact add --- .../repp/v1/domains/contacts_controller.rb | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/app/controllers/repp/v1/domains/contacts_controller.rb b/app/controllers/repp/v1/domains/contacts_controller.rb index 86cbf0acf..c41862b39 100644 --- a/app/controllers/repp/v1/domains/contacts_controller.rb +++ b/app/controllers/repp/v1/domains/contacts_controller.rb @@ -27,28 +27,21 @@ module Repp desc 'Link new contact(s) to domain' param_group :contacts_apidoc def create - contact_create_params[:contacts].each { |c| c[:action] = 'add' } - action = Actions::DomainUpdate.new(@domain, contact_create_params, current_user) - - unless action.call - handle_errors(@domain) - return - end - - render_success(data: { domain: { name: @domain.name } }) + cta('add') end api :DELETE, '/repp/v1/domains/:domain_name/contacts' desc 'Remove contact(s) from domain' param_group :contacts_apidoc def destroy - contact_create_params[:contacts].each { |c| c[:action] = 'rem' } + cta('rem') + end + + def cta(action = 'add') + contact_create_params[:contacts].each { |c| c[:action] = action } action = Actions::DomainUpdate.new(@domain, contact_create_params, current_user) - unless action.call - handle_errors(@domain) - return - end + handle_errors(@domain) and return unless action.call render_success(data: { domain: { name: @domain.name } }) end From 0d2cb6b7f27f2da2c2ad71b2c8b6cfe017c75e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 28 Jan 2021 11:07:12 +0200 Subject: [PATCH 37/80] REPP: Combine create/delete actions for DNSSEC keys --- .../repp/v1/domains/contacts_controller.rb | 2 ++ .../repp/v1/domains/dnssec_controller.rb | 23 ++++++++----------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/app/controllers/repp/v1/domains/contacts_controller.rb b/app/controllers/repp/v1/domains/contacts_controller.rb index c41862b39..2f8b7c1b4 100644 --- a/app/controllers/repp/v1/domains/contacts_controller.rb +++ b/app/controllers/repp/v1/domains/contacts_controller.rb @@ -41,7 +41,9 @@ module Repp contact_create_params[:contacts].each { |c| c[:action] = action } action = Actions::DomainUpdate.new(@domain, contact_create_params, current_user) + # rubocop:disable Style/AndOr handle_errors(@domain) and return unless action.call + # rubocop:enable Style/AndOr render_success(data: { domain: { name: @domain.name } }) end diff --git a/app/controllers/repp/v1/domains/dnssec_controller.rb b/app/controllers/repp/v1/domains/dnssec_controller.rb index ec3a3bd7f..0c30fd84f 100644 --- a/app/controllers/repp/v1/domains/dnssec_controller.rb +++ b/app/controllers/repp/v1/domains/dnssec_controller.rb @@ -25,15 +25,7 @@ module Repp param_group :dns_keys_apidoc, DnssecController end def create - dnssec_params[:dnssec][:dns_keys].each { |n| n[:action] = 'add' } - action = Actions::DomainUpdate.new(@domain, dnssec_params[:dnssec], current_user) - - unless action.call - handle_errors(@domain) - return - end - - render_success(data: { domain: { name: @domain.name } }) + cta('add') end api :DELETE, 'repp/v1/domains/:domain_name/dnssec' @@ -41,13 +33,16 @@ module Repp param_group :dns_keys_apidoc, DnssecController end def destroy - dnssec_params[:dnssec][:dns_keys].each { |n| n[:action] = 'rem' } + cta('rem') + end + + def cta(action = 'add') + dnssec_params[:dnssec][:dns_keys].each { |n| n[:action] = action } action = Actions::DomainUpdate.new(@domain, dnssec_params[:dnssec], current_user) - unless action.call - handle_errors(@domain) - return - end + # rubocop:disable Style/AndOr + (handle_errors(@domain) and return) unless action.call + # rubocop:enable Style/AndOr render_success(data: { domain: { name: @domain.name } }) end From 7c35083a8b6e9c786d5f6dd007d4a4d327d288ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 28 Jan 2021 11:35:35 +0200 Subject: [PATCH 38/80] Fix some CC issues --- .codeclimate.yml | 3 ++- app/controllers/repp/v1/base_controller.rb | 2 +- .../repp/v1/contacts_controller.rb | 2 +- .../repp/v1/domains/statuses_controller.rb | 20 +++++++++++-------- app/controllers/repp/v1/domains_controller.rb | 16 ++++++++------- app/models/actions/domain_create.rb | 13 +++++++++--- app/models/actions/domain_delete.rb | 10 +++++++--- app/models/actions/domain_renew.rb | 12 +++++------ 8 files changed, 48 insertions(+), 30 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 1b9e4ee26..346b01897 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -13,7 +13,8 @@ plugins: enabled: true config: languages: - - ruby + ruby: + mass_threshold: 26 - javascript eslint: enabled: true diff --git a/app/controllers/repp/v1/base_controller.rb b/app/controllers/repp/v1/base_controller.rb index 339d03311..05386b535 100644 --- a/app/controllers/repp/v1/base_controller.rb +++ b/app/controllers/repp/v1/base_controller.rb @@ -1,6 +1,6 @@ module Repp module V1 - class BaseController < ActionController::API + class BaseController < ActionController::API # rubocop:disable Metrics/ClassLength rescue_from ActiveRecord::RecordNotFound, with: :not_found_error before_action :authenticate_user before_action :validate_webclient_ca diff --git a/app/controllers/repp/v1/contacts_controller.rb b/app/controllers/repp/v1/contacts_controller.rb index f3e40a119..92f89a160 100644 --- a/app/controllers/repp/v1/contacts_controller.rb +++ b/app/controllers/repp/v1/contacts_controller.rb @@ -1,7 +1,7 @@ require 'serializers/repp/contact' module Repp module V1 - class ContactsController < BaseController + class ContactsController < BaseController # rubocop:disable Metrics/ClassLength before_action :find_contact, only: %i[show update destroy] api :get, '/repp/v1/contacts' diff --git a/app/controllers/repp/v1/domains/statuses_controller.rb b/app/controllers/repp/v1/domains/statuses_controller.rb index 1b1d47477..22e73df60 100644 --- a/app/controllers/repp/v1/domains/statuses_controller.rb +++ b/app/controllers/repp/v1/domains/statuses_controller.rb @@ -10,7 +10,7 @@ module Repp param :domain_name, String, required: true, desc: 'Domain name' param :status, String, required: true, desc: 'Status to be removed' def destroy - return editing_failed unless @domain.statuses.include?(params[:id]) + return editing_failed unless domain_with_status?(params[:id]) @domain.statuses = @domain.statuses.delete(params[:id]) if @domain.save @@ -25,18 +25,22 @@ module Repp param :domain_name, String, required: true, desc: 'Domain name' param :status, String, required: true, desc: 'Status to be added' def update - return editing_failed if @domain.statuses.include?(params[:id]) + return editing_failed if domain_with_status?(params[:id]) - @domain.statuses = @domain.statuses << params[:id] - # rubocop:disable Style/AndOr - handle_errors(@domain) and return unless @domain.save - # rubocop:enable Style/AndOr - - render_success(data: { domain: @domain.name, status: params[:id] }) + @domain.statuses << params[:id] + if @domain.save + render_success(data: { domain: @domain.name, status: params[:id] }) + else + handle_errors(@domain) + end end private + def domain_with_status? + @domain.statuses.include?(params[:id]) + end + def verify_status allowed_statuses = [DomainStatus::CLIENT_HOLD].freeze stat = params[:id] diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 8e77cd219..70970b7e1 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -1,7 +1,7 @@ require 'serializers/repp/domain' module Repp module V1 - class DomainsController < BaseController + class DomainsController < BaseController # rubocop:disable Metrics/ClassLength before_action :set_authorized_domain, only: %i[transfer_info destroy] before_action :forward_registrar_id, only: %i[create destroy] before_action :set_domain, only: %i[show update] @@ -11,13 +11,9 @@ module Repp def index records = current_user.registrar.domains domains = records.limit(limit).offset(offset) - domains = domains.pluck(:name) unless index_params[:details] == 'true' - if index_params[:details] == 'true' - domains = domains.map { |d| Serializers::Repp::Domain.new(d).to_json } - end - - render_success(data: { domains: domains, total_number_of_records: records.count }) + render_success(data: { domains: serialized_domains(domains), + total_number_of_records: records.count }) end api :GET, '/repp/v1/domains/:domain_name' @@ -136,6 +132,12 @@ module Repp private + def serialized_domains(domains) + return domains.pluck(:name) unless index_params[:details] == 'true' + + domains.map { |d| Serializers::Repp::Domain.new(d).to_json } + end + def initiate_transfer(transfer) domain = Epp::Domain.find_or_initialize_by(name: transfer[:domain_name]) action = Actions::DomainTransfer.new(domain, transfer[:transfer_code], diff --git a/app/models/actions/domain_create.rb b/app/models/actions/domain_create.rb index 274a070fb..0c3e19805 100644 --- a/app/models/actions/domain_create.rb +++ b/app/models/actions/domain_create.rb @@ -65,7 +65,7 @@ module Actions def assign_domain_attributes domain.name = params[:name].strip.downcase - domain.registrar = Registrar.find(params[:registrar_id]) + domain.registrar = current_registrar assign_domain_period assign_domain_auth_codes domain.dnskeys_attributes = params[:dnskeys_attributes] if params[:dnskeys_attributes] @@ -111,9 +111,12 @@ module Actions return unless domain.period period = Integer(domain.period) + domain.expire_time = calculate_expiry(period) + end + + def calculate_expiry(period) plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym - exp = (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day - domain.expire_time = exp + (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day end def action_billable? @@ -173,5 +176,9 @@ module Actions domain.errors.delete(:name_dirty) if domain.errors[:puny_label].any? domain.errors.any? end + + def current_registrar + Registrar.find(params[:registrar_id]) + end end end diff --git a/app/models/actions/domain_delete.rb b/app/models/actions/domain_delete.rb index f3197c452..929b1f6f7 100644 --- a/app/models/actions/domain_delete.rb +++ b/app/models/actions/domain_delete.rb @@ -39,11 +39,15 @@ module Actions true end + def ask_delete_verification + domain.registrant_verification_asked!(params, user.id) + domain.pending_delete! + domain.manage_automatic_statuses + end + def destroy if verify? - domain.registrant_verification_asked!(params, user.id) - domain.pending_delete! - domain.manage_automatic_statuses + ask_delete_verification else domain.set_pending_delete! end diff --git a/app/models/actions/domain_renew.rb b/app/models/actions/domain_renew.rb index ba1ac8fb3..047d24f17 100644 --- a/app/models/actions/domain_renew.rb +++ b/app/models/actions/domain_renew.rb @@ -11,15 +11,15 @@ module Actions end def call - renew + if !domain.renewable? || domain.invalid? + domain.add_renew_epp_errors + false + else + renew + end end def renew - if !domain.renewable? || domain.invalid? - domain.add_renew_epp_errors - return - end - task = Domains::BulkRenew::SingleDomainRenew.run(domain: domain, period: params[:period], unit: params[:period_unit], From dd8d4c10855515cb61c7afb3b1173fdb093ca69e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 28 Jan 2021 12:47:06 +0200 Subject: [PATCH 39/80] Fix CC issues --- .codeclimate.yml | 4 ++-- app/controllers/repp/v1/domains/contacts_controller.rb | 4 ++-- app/controllers/repp/v1/domains/dnssec_controller.rb | 6 +++--- app/controllers/repp/v1/domains/nameservers_controller.rb | 6 +++--- app/controllers/repp/v1/domains/renews_controller.rb | 2 +- app/controllers/repp/v1/domains/transfers_controller.rb | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 346b01897..c16179c86 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -12,9 +12,9 @@ plugins: duplication: enabled: true config: + count_threshold: 3 languages: - ruby: - mass_threshold: 26 + - ruby - javascript eslint: enabled: true diff --git a/app/controllers/repp/v1/domains/contacts_controller.rb b/app/controllers/repp/v1/domains/contacts_controller.rb index 2f8b7c1b4..b84e4bd46 100644 --- a/app/controllers/repp/v1/domains/contacts_controller.rb +++ b/app/controllers/repp/v1/domains/contacts_controller.rb @@ -38,7 +38,7 @@ module Repp end def cta(action = 'add') - contact_create_params[:contacts].each { |c| c[:action] = action } + params[:contacts].each { |c| c[:action] = action } action = Actions::DomainUpdate.new(@domain, contact_create_params, current_user) # rubocop:disable Style/AndOr @@ -76,7 +76,7 @@ module Repp private def contact_create_params - params.permit! + params.permit(:domain_id, contacts: [%i[action code type]]) end def contact_params diff --git a/app/controllers/repp/v1/domains/dnssec_controller.rb b/app/controllers/repp/v1/domains/dnssec_controller.rb index 0c30fd84f..491ce0a98 100644 --- a/app/controllers/repp/v1/domains/dnssec_controller.rb +++ b/app/controllers/repp/v1/domains/dnssec_controller.rb @@ -37,8 +37,8 @@ module Repp end def cta(action = 'add') - dnssec_params[:dnssec][:dns_keys].each { |n| n[:action] = action } - action = Actions::DomainUpdate.new(@domain, dnssec_params[:dnssec], current_user) + params[:dns_keys].each { |n| n[:action] = action } + action = Actions::DomainUpdate.new(@domain, dnssec_params, current_user) # rubocop:disable Style/AndOr (handle_errors(@domain) and return) unless action.call @@ -50,7 +50,7 @@ module Repp private def dnssec_params - params.permit! + params.permit(:domain_id, dns_keys: [%i[action flags protocol alg public_key]]) end end end diff --git a/app/controllers/repp/v1/domains/nameservers_controller.rb b/app/controllers/repp/v1/domains/nameservers_controller.rb index ce4227bab..0a907c04e 100644 --- a/app/controllers/repp/v1/domains/nameservers_controller.rb +++ b/app/controllers/repp/v1/domains/nameservers_controller.rb @@ -13,8 +13,8 @@ module Repp param :ipv6, Array, required: false, desc: 'Array of IPv6 values' end def create - nameserver_params[:nameservers].each { |n| n[:action] = 'add' } - action = Actions::DomainUpdate.new(@domain, params, current_user) + params[:nameservers].each { |n| n[:action] = 'add' } + action = Actions::DomainUpdate.new(@domain, nameserver_params, current_user) unless action.call handle_errors(@domain) @@ -45,7 +45,7 @@ module Repp end def nameserver_params - params.permit! + params.permit(:domain_id, nameservers: [[:hostname, :action, ipv4: [], ipv6: []]]) end end end diff --git a/app/controllers/repp/v1/domains/renews_controller.rb b/app/controllers/repp/v1/domains/renews_controller.rb index 74a9ad2e2..eabd9ea16 100644 --- a/app/controllers/repp/v1/domains/renews_controller.rb +++ b/app/controllers/repp/v1/domains/renews_controller.rb @@ -36,7 +36,7 @@ module Repp private def renew_params - params.permit! + params.permit(:domain_id, renew: %i[period period_unit]) end def validate_renew_period diff --git a/app/controllers/repp/v1/domains/transfers_controller.rb b/app/controllers/repp/v1/domains/transfers_controller.rb index 2594205d6..e9474d94d 100644 --- a/app/controllers/repp/v1/domains/transfers_controller.rb +++ b/app/controllers/repp/v1/domains/transfers_controller.rb @@ -31,7 +31,7 @@ module Repp end def transfer_params - params.permit! + params.permit(:domain_id, transfer: [:transfer_code]) end end end From c5e2ebe15ecce53a4cb05dd71c76f7febc6920c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 29 Jan 2021 15:11:13 +0200 Subject: [PATCH 40/80] Fix BL after master emrge --- app/controllers/repp/v1/domains_controller.rb | 7 +++++-- app/models/actions/domain_create.rb | 13 ++++--------- app/models/actions/domain_update.rb | 19 +++++-------------- app/models/dnskey.rb | 8 ++++++++ lib/deserializers/xml/domain_update.rb | 7 ++----- 5 files changed, 24 insertions(+), 30 deletions(-) diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 86d8e9d76..e8fdb040f 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -214,8 +214,11 @@ module Repp end def domain_create_params - params.require(:domain).require(%i[name registrant_id period period_unit]) - params.require(:domain).permit(%i[name registrant_id period period_unit registrar_id]) + params.require(:domain).permit(:name, :registrant_id, :period, :period_unit, :registrar_id, + dnskeys_attributes: [%i[flags alg protocol public_key]], + nameservers_attributes: [[:hostname, ipv4: [], ipv6: []]], + admin_domain_contacts_attributes: [], + tech_domain_contacts_attributes: []) end end end diff --git a/app/models/actions/domain_create.rb b/app/models/actions/domain_create.rb index c2597cffc..883f8d33d 100644 --- a/app/models/actions/domain_create.rb +++ b/app/models/actions/domain_create.rb @@ -74,18 +74,13 @@ module Actions def assign_dnskeys return unless params[:dnskeys_attributes]&.any? - params[:dnskeys_attributes].each { |dk| verify_public_key_integrity(dk) } - params.dnskeys_attributes = params[:dnskeys_attributes] + params[:dnskeys_attributes].each { |dk| verify_public_key_integrity(dk[:public_key]) } + domain.dnskeys_attributes = params[:dnskeys_attributes] end - def verify_public_key_integrity(dnssec) - return if dnssec[:public_key].blank? + def verify_public_key_integrity(pub) + return if Dnskey.pub_key_base64?(pub) - value = dnssec[:public_key] - if !value.is_a?(String) || Base64.strict_encode64(Base64.strict_decode64(value)) != value - domain.add_epp_error(2005, nil, nil, %i[dnskeys invalid]) - end - rescue ArgumentError domain.add_epp_error(2005, nil, nil, %i[dnskeys invalid]) end diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index 7a9223c81..760ea644f 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -14,7 +14,7 @@ module Actions assign_new_registrant if params[:registrant] assign_relational_modifications assign_requested_statuses - maybe_attach_legal_doc + Actions::BaseAction.maybe_attach_legal_doc(domain, params[:legal_document]) commit end @@ -98,7 +98,7 @@ module Actions domain.add_epp_error('2306', nil, nil, %i[dnskeys ds_data_not_allowed]) end - verify_public_key_integrity(key) + verify_public_key_integrity(key[:public_key]) @dnskeys << key.except(:action) end @@ -216,10 +216,6 @@ module Actions end end - def maybe_attach_legal_doc - Actions::BaseAction.maybe_attach_legal_doc(domain, params[:legal_document]) - end - def ask_registrant_verification if verify_registrant_change? && !bypass_verify && Setting.request_confirmation_on_registrant_change_enabled @@ -243,15 +239,10 @@ module Actions false end - def verify_public_key_integrity(dnssec) - return if dnssec[:public_key].blank? + def verify_public_key_integrity(pub) + return if Dnskey.pub_key_base64?(pub) - value = dnssec[:public_key] - if !value.is_a?(String) || Base64.strict_encode64(Base64.strict_decode64(value)) != value - domain.add_epp_error('2005', nil, nil, %i[dnskeys invalid]) - end - rescue ArgumentError - domain.add_epp_error('2005', nil, nil, %i[dnskeys invalid]) + domain.add_epp_error(2005, nil, nil, %i[dnskeys invalid]) end end end diff --git a/app/models/dnskey.rb b/app/models/dnskey.rb index c0f3f7491..a40225fd2 100644 --- a/app/models/dnskey.rb +++ b/app/models/dnskey.rb @@ -128,5 +128,13 @@ class Dnskey < ApplicationRecord def bin_to_hex(s) s.each_byte.map { |b| format('%02X', b) }.join end + + def pub_key_base64?(pub) + return unless pub&.is_a?(String) + + Base64.strict_encode64(Base64.strict_decode64(pub)) == pub + rescue ArgumentError + false + end end end diff --git a/lib/deserializers/xml/domain_update.rb b/lib/deserializers/xml/domain_update.rb index 62b528bd7..86250a368 100644 --- a/lib/deserializers/xml/domain_update.rb +++ b/lib/deserializers/xml/domain_update.rb @@ -10,13 +10,14 @@ module Deserializers def initialize(frame, registrar) @frame = frame @registrar = registrar + @legal_document ||= ::Deserializers::Xml::LegalDocument.new(frame).call end def call obj = { domain: frame.css('name')&.text, registrant: registrant, contacts: contacts, auth_info: if_present('authInfo > pw'), nameservers: nameservers, registrar_id: registrar, statuses: statuses, dns_keys: dns_keys, - reserved_pw: if_present('reserved > pw'), legal_document: legal_document } + reserved_pw: if_present('reserved > pw'), legal_document: @legal_document } obj.reject { |_key, val| val.blank? } end @@ -78,10 +79,6 @@ module Deserializers s end - def legal_document - @legal_document ||= ::Deserializers::Xml::LegalDocument.new(frame).call - end - def if_present(css_path) return if frame.css(css_path).blank? From bad06307b67e1b24320684670835fe716c6a0059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 1 Feb 2021 12:35:20 +0200 Subject: [PATCH 41/80] REPP: Test domain status editing --- .../repp/v1/domains/statuses_controller.rb | 12 +-- .../repp/v1/domains/statuses_test.rb | 82 +++++++++++++++++++ 2 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 test/integration/repp/v1/domains/statuses_test.rb diff --git a/app/controllers/repp/v1/domains/statuses_controller.rb b/app/controllers/repp/v1/domains/statuses_controller.rb index 22e73df60..ee15655df 100644 --- a/app/controllers/repp/v1/domains/statuses_controller.rb +++ b/app/controllers/repp/v1/domains/statuses_controller.rb @@ -6,9 +6,9 @@ module Repp before_action :verify_status api :DELETE, '/repp/v1/domains/:domain_name/statuses/:status' + param :domain_name, String, desc: 'Domain name' + param :status, String, desc: 'Status to be removed' desc 'Remove status from specific domain' - param :domain_name, String, required: true, desc: 'Domain name' - param :status, String, required: true, desc: 'Status to be removed' def destroy return editing_failed unless domain_with_status?(params[:id]) @@ -21,9 +21,9 @@ module Repp end api :PUT, '/repp/v1/domains/:domain_name/statuses/:status' + param :domain_name, String, desc: 'Domain name' + param :status, String, desc: 'Status to be added' desc 'Add status to specific domain' - param :domain_name, String, required: true, desc: 'Domain name' - param :status, String, required: true, desc: 'Status to be added' def update return editing_failed if domain_with_status?(params[:id]) @@ -37,8 +37,8 @@ module Repp private - def domain_with_status? - @domain.statuses.include?(params[:id]) + def domain_with_status?(status) + @domain.statuses.include?(status) end def verify_status diff --git a/test/integration/repp/v1/domains/statuses_test.rb b/test/integration/repp/v1/domains/statuses_test.rb new file mode 100644 index 000000000..271752ae3 --- /dev/null +++ b/test/integration/repp/v1/domains/statuses_test.rb @@ -0,0 +1,82 @@ +require 'test_helper' + +class ReppV1DomainsStatusesTest < ActionDispatch::IntegrationTest + def setup + @user = users(:api_bestnames) + @domain = domains(:shop) + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + token = "Basic #{token}" + + @auth_headers = { 'Authorization' => token } + end + + def test_client_hold_can_be_added + refute @domain.statuses.include?(DomainStatus::CLIENT_HOLD) + put repp_v1_domain_status_path(domain_id: @domain.name, id: DomainStatus::CLIENT_HOLD), headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + @domain.reload + + assert @domain.statuses.include?(DomainStatus::CLIENT_HOLD) + end + + def test_client_hold_can_be_removed + statuses = @domain.statuses << DomainStatus::CLIENT_HOLD + @domain.update(statuses: statuses) + delete repp_v1_domain_status_path(domain_id: @domain.name, id: DomainStatus::CLIENT_HOLD), headers: @auth_headers + + assert_response :ok + @domain.reload + refute @domain.statuses.include?(DomainStatus::CLIENT_HOLD) + end + + def test_can_not_remove_disallowed_statuses + statuses = @domain.statuses << DomainStatus::FORCE_DELETE + @domain.update(statuses: statuses) + + delete repp_v1_domain_status_path(domain_id: @domain.name, id: DomainStatus::FORCE_DELETE), headers: @auth_headers + @domain.reload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 'Parameter value policy error. Client-side object status management not supported: status serverForceDelete', json[:message] + + assert @domain.statuses.include?(DomainStatus::FORCE_DELETE) + end + + def test_can_not_add_disallowed_statuses + put repp_v1_domain_status_path(domain_id: @domain.name, id: DomainStatus::DELETE_CANDIDATE), headers: @auth_headers + @domain.reload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 'Parameter value policy error. Client-side object status management not supported: status deleteCandidate', json[:message] + + refute @domain.statuses.include?(DomainStatus::DELETE_CANDIDATE) + end + + def test_can_not_remove_unexistant_status + refute @domain.statuses.include?(DomainStatus::CLIENT_HOLD) + delete repp_v1_domain_status_path(domain_id: @domain.name, id: DomainStatus::CLIENT_HOLD), headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 'Parameter value policy error. Client-side object status management not supported: status clientHold', json[:message] + end + + def test_returns_normal_error_when_action_fails + @invalid_domain = domains(:invalid) + + put repp_v1_domain_status_path(domain_id: @invalid_domain.name, id: DomainStatus::CLIENT_HOLD), headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + assert_response :bad_request + assert_equal 2304, json[:code] + + delete repp_v1_domain_status_path(domain_id: @invalid_domain.name, id: DomainStatus::FORCE_DELETE), headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + assert_response :bad_request + assert_equal 2306, json[:code] + end + +end From 4c7f9709ad4df981c496a3feaeba991587b1ff55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 1 Feb 2021 13:16:39 +0200 Subject: [PATCH 42/80] REPP: Test domain nameserver actions --- .../repp/v1/domains/nameservers_test.rb | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 test/integration/repp/v1/domains/nameservers_test.rb diff --git a/test/integration/repp/v1/domains/nameservers_test.rb b/test/integration/repp/v1/domains/nameservers_test.rb new file mode 100644 index 000000000..9bb75ce1d --- /dev/null +++ b/test/integration/repp/v1/domains/nameservers_test.rb @@ -0,0 +1,94 @@ +require 'test_helper' + +class ReppV1DomainsStatusesTest < ActionDispatch::IntegrationTest + def setup + @user = users(:api_bestnames) + @domain = domains(:shop) + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + token = "Basic #{token}" + + @auth_headers = { 'Authorization' => token } + end + + def test_can_add_new_nameserver + payload = { + nameservers: [ + { hostname: "ns1.domeener.ee", + ipv4: ["192.168.1.1"], + ipv6: ["FE80::AEDE:48FF:FE00:1122"]} + ] + } + + post "/repp/v1/domains/#{@domain.name}/nameservers", params: payload, headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + assert_equal payload[:nameservers][0][:hostname], @domain.nameservers.last.hostname + assert_equal payload[:nameservers][0][:ipv4], @domain.nameservers.last.ipv4 + assert_equal payload[:nameservers][0][:ipv6], @domain.nameservers.last.ipv6 + end + + def test_can_remove_existing_nameserver + payload = { + nameservers: [ + { hostname: "ns1.domeener.ee", + ipv4: ["192.168.1.1"], + ipv6: ["FE80::AEDE:48FF:FE00:1122"]} + ] + } + + post "/repp/v1/domains/#{@domain.name}/nameservers", params: payload, headers: @auth_headers + assert_response :ok + + @domain.reload + assert @domain.nameservers.where(hostname: payload[:nameservers][0][:hostname]).any? + + delete "/repp/v1/domains/#{@domain.name}/nameservers/#{payload[:nameservers][0][:hostname]}", + params: payload, headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + @domain.reload + refute @domain.nameservers.where(hostname: payload[:nameservers][0][:hostname]).any? + end + + def test_can_not_add_duplicate_nameserver + payload = { + nameservers: [ + { hostname: @domain.nameservers.last.hostname, + ipv4: @domain.nameservers.last.ipv4, + ipv6: @domain.nameservers.last.ipv6 } + ] + } + + post "/repp/v1/domains/#{@domain.name}/nameservers", params: payload, headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + assert_response :bad_request + assert_equal 2302, json[:code] + assert_equal 'Nameserver already exists on this domain [hostname]', json[:message] + end + + def test_returns_errors_when_removing_unknown_nameserver + delete "/repp/v1/domains/#{@domain.name}/nameservers/ns.nonexistant.test", headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :not_found + assert_equal 2303, json[:code] + assert_equal 'Object does not exist', json[:message] + end + + def test_returns_error_when_ns_count_too_low + delete "/repp/v1/domains/#{@domain.name}/nameservers/#{@domain.nameservers.last.hostname}", headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 2308, json[:code] + assert_equal 'Data management policy violation; Nameserver count must be between 2-11 for active ' \ + 'domains [nameservers]', json[:message] + end +end From b3cf665ed501087ddb0ce0d6a60e126a32b84803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 1 Feb 2021 14:40:36 +0200 Subject: [PATCH 43/80] REPP: Domain contacts test --- app/models/actions/domain_update.rb | 12 ++- .../repp/v1/contacts/tech_replace_test.rb | 50 +++++++++ .../repp/v1/domains/contacts_test.rb | 100 ++++++++++++++++++ .../repp/v1/domains/nameservers_test.rb | 2 +- 4 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 test/integration/repp/v1/contacts/tech_replace_test.rb create mode 100644 test/integration/repp/v1/domains/contacts_test.rb diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index 760ea644f..4131c4f51 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -22,7 +22,10 @@ module Actions def assign_relational_modifications assign_nameserver_modifications if params[:nameservers] assign_dnssec_modifications if params[:dns_keys] - (assign_admin_contact_changes && assign_tech_contact_changes) if params[:contacts] + return unless params[:contacts] + + assign_admin_contact_changes + assign_tech_contact_changes end def validate_domain_integrity @@ -147,10 +150,11 @@ module Actions end def contact_for_action(action:, method:, code:) - return Epp::Contact.find_by(code: code) if action == 'add' - return domain.admin_domain_contacts.find_by(contact_code_cache: code) if method == 'admin' + contact = Epp::Contact.find_by(code: code) + return contact if action == 'add' || !contact + return domain.admin_domain_contacts.find_by(contact_id: contact.id) if method == 'admin' - domain.tech_domain_contacts.find_by(contact_code_cache: code) + domain.tech_domain_contacts.find_by(contact_id: contact.id) end def assign_contact(obj, add: false, admin: true, code:) diff --git a/test/integration/repp/v1/contacts/tech_replace_test.rb b/test/integration/repp/v1/contacts/tech_replace_test.rb new file mode 100644 index 000000000..dfc61f6e2 --- /dev/null +++ b/test/integration/repp/v1/contacts/tech_replace_test.rb @@ -0,0 +1,50 @@ +require 'test_helper' + +class ReppV1ContactsTechReplaceTest < ActionDispatch::IntegrationTest + def setup + @user = users(:api_bestnames) + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + token = "Basic #{token}" + + @auth_headers = { 'Authorization' => token } + end + + def test_replaces_tech_contacts + old_contact = contacts(:john) + new_contact = contacts(:william) + + assert DomainContact.where(contact: old_contact, type: 'TechDomainContact').any? + + payload = { current_contact_id: old_contact.code, new_contact_id: new_contact.code} + patch "/repp/v1/domains/contacts", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + assert_empty ["hospital.test", "library.test"] - json[:data][:affected_domains] + + assert DomainContact.where(contact: old_contact, type: 'TechDomainContact').blank? + end + + def test_validates_contact_codes + payload = { current_contact_id: 'aaa', new_contact_id: 'bbb'} + patch "/repp/v1/domains/contacts", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :not_found + assert_equal 2303, json[:code] + assert_equal 'Object does not exist', json[:message] + end + + def test_new_contact_must_be_different + old_contact = contacts(:john) + + payload = { current_contact_id: old_contact.code, new_contact_id: old_contact.code } + patch "/repp/v1/domains/contacts", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 2304, json[:code] + assert_equal 'New contact must be different from current', json[:message] + end +end diff --git a/test/integration/repp/v1/domains/contacts_test.rb b/test/integration/repp/v1/domains/contacts_test.rb new file mode 100644 index 000000000..b9b26a745 --- /dev/null +++ b/test/integration/repp/v1/domains/contacts_test.rb @@ -0,0 +1,100 @@ +require 'test_helper' + +class ReppV1DomainsContactsTest < ActionDispatch::IntegrationTest + def setup + @user = users(:api_bestnames) + @domain = domains(:shop) + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + token = "Basic #{token}" + + @auth_headers = { 'Authorization' => token } + end + + def test_shows_existing_domain_contacts + get "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + assert_equal @domain.admin_contacts.length, json[:data][:admin_contacts].length + assert_equal @domain.tech_contacts.length, json[:data][:tech_contacts].length + end + + def test_can_add_new_admin_contacts + new_contact = contacts(:john) + refute @domain.admin_contacts.find_by(code: new_contact.code).present? + + payload = { contacts: [ { code: new_contact.code, type: 'admin' } ] } + post "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + + assert @domain.admin_contacts.find_by(code: new_contact.code).present? + end + + def test_can_add_new_tech_contacts + new_contact = contacts(:john) + refute @domain.tech_contacts.find_by(code: new_contact.code).present? + + payload = { contacts: [ { code: new_contact.code, type: 'tech' } ] } + post "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + @domain.reload + + assert @domain.tech_contacts.find_by(code: new_contact.code).present? + end + + def test_can_remove_admin_contacts + contact = contacts(:john) + payload = { contacts: [ { code: contact.code, type: 'admin' } ] } + post "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload + assert @domain.admin_contacts.find_by(code: contact.code).present? + + # Actually delete the contact + delete "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + + refute @domain.admin_contacts.find_by(code: contact.code).present? + end + + def test_can_remove_tech_contacts + contact = contacts(:john) + payload = { contacts: [ { code: contact.code, type: 'tech' } ] } + post "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload + assert @domain.tech_contacts.find_by(code: contact.code).present? + + # Actually delete the contact + delete "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + + refute @domain.tech_contacts.find_by(code: contact.code).present? + end + + def test_can_not_remove_one_and_only_contact + contact = @domain.admin_contacts.last + + payload = { contacts: [ { code: contact.code, type: 'admin' } ] } + delete "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + @domain.reload + assert_response :bad_request + assert_equal 2004, json[:code] + + assert @domain.admin_contacts.any? + end + +end diff --git a/test/integration/repp/v1/domains/nameservers_test.rb b/test/integration/repp/v1/domains/nameservers_test.rb index 9bb75ce1d..780e889c1 100644 --- a/test/integration/repp/v1/domains/nameservers_test.rb +++ b/test/integration/repp/v1/domains/nameservers_test.rb @@ -1,6 +1,6 @@ require 'test_helper' -class ReppV1DomainsStatusesTest < ActionDispatch::IntegrationTest +class ReppV1DomainsNameserversTest < ActionDispatch::IntegrationTest def setup @user = users(:api_bestnames) @domain = domains(:shop) From d838e561129507af9da1e7a2b8a97b456b1cd89e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 1 Feb 2021 15:49:59 +0200 Subject: [PATCH 44/80] REPP: Domain renew tests --- app/models/actions/domain_renew.rb | 1 - .../repp/v1/domains/renews_test.rb | 44 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 test/integration/repp/v1/domains/renews_test.rb diff --git a/app/models/actions/domain_renew.rb b/app/models/actions/domain_renew.rb index 047d24f17..9ad11efaf 100644 --- a/app/models/actions/domain_renew.rb +++ b/app/models/actions/domain_renew.rb @@ -24,7 +24,6 @@ module Actions period: params[:period], unit: params[:period_unit], registrar: user) - task.valid? end end diff --git a/test/integration/repp/v1/domains/renews_test.rb b/test/integration/repp/v1/domains/renews_test.rb new file mode 100644 index 000000000..3f78907db --- /dev/null +++ b/test/integration/repp/v1/domains/renews_test.rb @@ -0,0 +1,44 @@ +require 'test_helper' + +class ReppV1DomainsRenewsTest < ActionDispatch::IntegrationTest + def setup + @user = users(:api_bestnames) + @domain = domains(:shop) + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + token = "Basic #{token}" + + @auth_headers = { 'Authorization' => token } + end + + def test_domain_can_be_renewed + original_valid_to = @domain.valid_to + travel_to Time.zone.parse('2010-07-05') + + @auth_headers['Content-Type'] = 'application/json' + payload = { renew: { period: 1, period_unit: 'y' } } + post "/repp/v1/domains/#{@domain.name}/renew", headers: @auth_headers, params: payload.to_json + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + assert @domain.valid_to, original_valid_to + 1.year + end + + def test_domain_renew_pricing_error + original_valid_to = @domain.valid_to + travel_to Time.zone.parse('2010-07-05') + + @auth_headers['Content-Type'] = 'application/json' + payload = { renew: { period: 100, period_unit: 'y' } } + post "/repp/v1/domains/#{@domain.name}/renew", headers: @auth_headers, params: payload.to_json + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 2104, json[:code] + assert_equal 'Active price missing for this operation!', json[:message] + + assert @domain.valid_to, original_valid_to + end +end From 8bb70fb005a2b2f409d6780fb0fd08d40a0933a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 1 Feb 2021 16:07:49 +0200 Subject: [PATCH 45/80] REPP: Domain DNSSEC key manipulation tests --- .../repp/v1/domains/dnssec_test.rb | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 test/integration/repp/v1/domains/dnssec_test.rb diff --git a/test/integration/repp/v1/domains/dnssec_test.rb b/test/integration/repp/v1/domains/dnssec_test.rb new file mode 100644 index 000000000..cced7e646 --- /dev/null +++ b/test/integration/repp/v1/domains/dnssec_test.rb @@ -0,0 +1,96 @@ +require 'test_helper' + +class ReppV1DomainsDnssecTest < ActionDispatch::IntegrationTest + def setup + @user = users(:api_bestnames) + @domain = domains(:shop) + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + token = "Basic #{token}" + + @auth_headers = { 'Authorization' => token } + end + + def test_shows_dnssec_keys_associated_with_domain + get "/repp/v1/domains/#{@domain.name}/dnssec", headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + assert_empty json[:data][:dns_keys] + + payload = { + dns_keys: [ + { flags: '256', + alg: '14', + protocol: '3', + public_key: 'dGVzdA==' + } + ] + } + + post "/repp/v1/domains/#{@domain.name}/dnssec", params: payload, headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + get "/repp/v1/domains/#{@domain.name}/dnssec", headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_equal 1, json[:data][:dns_keys].length + end + + def test_creates_dnssec_key_successfully + assert @domain.dnskeys.empty? + payload = { + dns_keys: [ + { flags: '256', + alg: '14', + protocol: '3', + public_key: 'dGVzdA==' + } + ] + } + + post "/repp/v1/domains/#{@domain.name}/dnssec", params: payload, headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + @domain.reload + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + assert @domain.dnskeys.present? + dnssec_key = @domain.dnskeys.last + assert_equal payload[:dns_keys][0][:flags].to_i, dnssec_key.flags + assert_equal payload[:dns_keys][0][:alg].to_i, dnssec_key.alg + assert_equal payload[:dns_keys][0][:protocol].to_i, dnssec_key.protocol + assert_equal payload[:dns_keys][0][:public_key], dnssec_key.public_key + end + + def test_removes_existing_dnssec_key_successfully + payload = { + dns_keys: [ + { flags: '256', + alg: '14', + protocol: '3', + public_key: 'dGVzdA==' + } + ] + } + + post "/repp/v1/domains/#{@domain.name}/dnssec", params: payload, headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert @domain.dnskeys.any? + + # Real delete here + delete "/repp/v1/domains/#{@domain.name}/dnssec", params: payload, headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + @domain.reload + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + assert @domain.dnskeys.empty? + end +end From f46f4aac84f2632fa78c5f3403b7a9fd23e888d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 1 Feb 2021 16:29:03 +0200 Subject: [PATCH 46/80] REPP: Registrar Poll notifications test --- .../repp/v1/registrar/notifications_test.rb | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 test/integration/repp/v1/registrar/notifications_test.rb diff --git a/test/integration/repp/v1/registrar/notifications_test.rb b/test/integration/repp/v1/registrar/notifications_test.rb new file mode 100644 index 000000000..9fafca443 --- /dev/null +++ b/test/integration/repp/v1/registrar/notifications_test.rb @@ -0,0 +1,50 @@ +require 'test_helper' + +class ReppV1RegistrarNotificationsTest < ActionDispatch::IntegrationTest + def setup + @user = users(:api_bestnames) + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + token = "Basic #{token}" + + @auth_headers = { 'Authorization' => token } + end + + def test_gets_latest_unread_poll_message + notification = @user.registrar.notifications.where(read: false).order(created_at: :desc).first + get "/repp/v1/registrar/notifications", headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + assert_equal notification.text, json[:data][:text] + end + + def test_can_read_specific_notification_by_id + notification = @user.registrar.notifications.order(created_at: :desc).second + + get "/repp/v1/registrar/notifications/#{notification.id}", headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + assert_equal notification.text, json[:data][:text] + end + + def test_can_mark_notification_as_read + @auth_headers['Content-Type'] = 'application/json' + notification = @user.registrar.notifications.where(read: false).order(created_at: :desc).first + + payload = { notification: { read: true} } + put "/repp/v1/registrar/notifications/#{notification.id}", headers: @auth_headers, params: payload.to_json + json = JSON.parse(response.body, symbolize_names: true) + notification.reload + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + assert_equal notification.id, json[:data][:notification_id] + assert_equal notification.read, json[:data][:read] + end +end From 6a8eaaf131707b6be90dfd4159ccd3259d8b8b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 1 Feb 2021 16:47:05 +0200 Subject: [PATCH 47/80] REPP: Scoped domain transfer test --- .../repp/v1/domains/transfer_test.rb | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/integration/repp/v1/domains/transfer_test.rb b/test/integration/repp/v1/domains/transfer_test.rb index 46d5c30c4..a86395083 100644 --- a/test/integration/repp/v1/domains/transfer_test.rb +++ b/test/integration/repp/v1/domains/transfer_test.rb @@ -10,6 +10,34 @@ class ReppV1DomainsTransferTest < ActionDispatch::IntegrationTest @auth_headers = { 'Authorization' => token } end + def test_transfers_scoped_domain + refute @domain.registrar == @user.registrar + payload = { transfer: { transfer_code: @domain.transfer_code } } + post "/repp/v1/domains/#{@domain.name}/transfer", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + @domain.reload + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + assert_equal @domain.registrar, @user.registrar + end + + def test_does_not_transfer_scoped_domain_with_invalid_transfer_code + refute @domain.registrar == @user.registrar + payload = { transfer: { transfer_code: 'invalid' } } + post "/repp/v1/domains/#{@domain.name}/transfer", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + @domain.reload + + assert_response :bad_request + assert_equal 2202, json[:code] + assert_equal 'Invalid authorization information', json[:message] + + refute @domain.registrar == @user.registrar + end + def test_transfers_domain payload = { "data": { From 095da29e98d7e69d0104e531bbe949793caddae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 1 Feb 2021 17:24:41 +0200 Subject: [PATCH 48/80] REPP: Domain create test --- .../repp/v1/domains/create_test.rb | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 test/integration/repp/v1/domains/create_test.rb diff --git a/test/integration/repp/v1/domains/create_test.rb b/test/integration/repp/v1/domains/create_test.rb new file mode 100644 index 000000000..f3cd4808f --- /dev/null +++ b/test/integration/repp/v1/domains/create_test.rb @@ -0,0 +1,113 @@ +require 'test_helper' + +class ReppV1DomainsCreateTest < ActionDispatch::IntegrationTest + def setup + @user = users(:api_bestnames) + @domain = domains(:shop) + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + token = "Basic #{token}" + + @auth_headers = { 'Authorization' => token } + end + + def test_creates_new_domain_successfully + @auth_headers['Content-Type'] = 'application/json' + contact = contacts(:john) + + payload = { + domain: { + name: 'domeener.test', + registrant_id: contact.code, + period: 1, + period_unit: 'y' + } + } + + post "/repp/v1/domains", headers: @auth_headers, params: payload.to_json + json = JSON.parse(response.body, symbolize_names: true) + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + assert @user.registrar.domains.find_by(name: 'domeener.test').present? + end + + def test_validates_price_on_domain_create + @auth_headers['Content-Type'] = 'application/json' + contact = contacts(:john) + + payload = { + domain: { + name: 'domeener.test', + registrant_id: contact.code, + period: 3, + period_unit: 'y' + } + } + + post "/repp/v1/domains", headers: @auth_headers, params: payload.to_json + json = JSON.parse(response.body, symbolize_names: true) + assert_response :bad_request + assert_equal 2104, json[:code] + assert_equal 'Active price missing for this operation!', json[:message] + + refute @user.registrar.domains.find_by(name: 'domeener.test').present? + end + + def test_creates_domain_with_predefined_nameservers + @auth_headers['Content-Type'] = 'application/json' + contact = contacts(:john) + + payload = { + domain: { + name: 'domeener.test', + registrant_id: contact.code, + period: 1, + period_unit: 'y', + nameservers_attributes: [ + { hostname: 'ns1.domeener.ee' }, + { hostname: 'ns2.domeener.ee' } + ] + } + } + + post "/repp/v1/domains", headers: @auth_headers, params: payload.to_json + json = JSON.parse(response.body, symbolize_names: true) + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + domain = @user.registrar.domains.find_by(name: 'domeener.test') + assert domain.present? + assert_empty ['ns1.domeener.ee', 'ns2.domeener.ee'] - domain.nameservers.collect(&:hostname) + end + + def test_creates_domain_with_custom_contacts + @auth_headers['Content-Type'] = 'application/json' + contact = contacts(:john) + admin_contact = contacts(:william) + tech_contact = contacts(:jane) + + payload = { + domain: { + name: 'domeener.test', + registrant_id: contact.code, + period: 1, + period_unit: 'y', + admin_domain_contacts_attributes: [ admin_contact.code ], + tech_domain_contacts_attributes: [ tech_contact.code ], + } + } + + post "/repp/v1/domains", headers: @auth_headers, params: payload.to_json + json = JSON.parse(response.body, symbolize_names: true) + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + domain = @user.registrar.domains.find_by(name: 'domeener.test') + assert domain.present? + assert_equal tech_contact, domain.tech_domain_contacts.first.contact + assert_equal admin_contact, domain.admin_domain_contacts.first.contact + end +end From 92db43db183a442c38f314597fd004d3fad692ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 2 Feb 2021 10:36:03 +0200 Subject: [PATCH 49/80] REPP: Domain list test --- test/integration/repp/v1/domains/list_test.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/integration/repp/v1/domains/list_test.rb b/test/integration/repp/v1/domains/list_test.rb index bee390e5c..366ac4d26 100644 --- a/test/integration/repp/v1/domains/list_test.rb +++ b/test/integration/repp/v1/domains/list_test.rb @@ -51,4 +51,17 @@ class ReppV1DomainsListTest < ActionDispatch::IntegrationTest assert_equal (@user.registrar.domains.count - offset), json[:data][:domains].length end + + def test_returns_specific_domain_details_by_name + domain = domains(:shop) + get "/repp/v1/domains/#{domain.name}", headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + serialized_domain = Serializers::Repp::Domain.new(domain).to_json + assert_equal serialized_domain.as_json, json[:data][:domain].as_json + end end From 1461d2a5664ad5fe0f74d7a034780b14a9a938f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 2 Feb 2021 11:26:52 +0200 Subject: [PATCH 50/80] REPP: Domain registrant change test --- .../repp/v1/domains/contacts_controller.rb | 2 +- .../repp/v1/domains/dnssec_controller.rb | 2 +- .../repp/v1/domains/nameservers_controller.rb | 2 +- app/controllers/repp/v1/domains_controller.rb | 2 +- app/models/actions/domain_update.rb | 1 - .../repp/v1/domains/update_test.rb | 85 +++++++++++++++++++ 6 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 test/integration/repp/v1/domains/update_test.rb diff --git a/app/controllers/repp/v1/domains/contacts_controller.rb b/app/controllers/repp/v1/domains/contacts_controller.rb index b84e4bd46..f2e5e4018 100644 --- a/app/controllers/repp/v1/domains/contacts_controller.rb +++ b/app/controllers/repp/v1/domains/contacts_controller.rb @@ -39,7 +39,7 @@ module Repp def cta(action = 'add') params[:contacts].each { |c| c[:action] = action } - action = Actions::DomainUpdate.new(@domain, contact_create_params, current_user) + action = Actions::DomainUpdate.new(@domain, contact_create_params, false) # rubocop:disable Style/AndOr handle_errors(@domain) and return unless action.call diff --git a/app/controllers/repp/v1/domains/dnssec_controller.rb b/app/controllers/repp/v1/domains/dnssec_controller.rb index 491ce0a98..fcfaa991a 100644 --- a/app/controllers/repp/v1/domains/dnssec_controller.rb +++ b/app/controllers/repp/v1/domains/dnssec_controller.rb @@ -38,7 +38,7 @@ module Repp def cta(action = 'add') params[:dns_keys].each { |n| n[:action] = action } - action = Actions::DomainUpdate.new(@domain, dnssec_params, current_user) + action = Actions::DomainUpdate.new(@domain, dnssec_params, false) # rubocop:disable Style/AndOr (handle_errors(@domain) and return) unless action.call diff --git a/app/controllers/repp/v1/domains/nameservers_controller.rb b/app/controllers/repp/v1/domains/nameservers_controller.rb index 0a907c04e..fe38de93c 100644 --- a/app/controllers/repp/v1/domains/nameservers_controller.rb +++ b/app/controllers/repp/v1/domains/nameservers_controller.rb @@ -28,7 +28,7 @@ module Repp desc 'Delete specific nameserver from domain' def destroy nameserver = { nameservers: [{ hostname: params[:id], action: 'rem' }] } - action = Actions::DomainUpdate.new(@domain, nameserver, current_user) + action = Actions::DomainUpdate.new(@domain, nameserver, false) unless action.call handle_errors(@domain) diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index e8fdb040f..3db71c23b 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -76,7 +76,7 @@ module Repp param :auth_info, String, required: false, desc: 'New authorization code' end def update - action = Actions::DomainUpdate.new(@domain, params[:domain], current_user) + action = Actions::DomainUpdate.new(@domain, params[:domain], false) unless action.call handle_errors(@domain) diff --git a/app/models/actions/domain_update.rb b/app/models/actions/domain_update.rb index 4131c4f51..d54bb99da 100644 --- a/app/models/actions/domain_update.rb +++ b/app/models/actions/domain_update.rb @@ -223,7 +223,6 @@ module Actions def ask_registrant_verification if verify_registrant_change? && !bypass_verify && Setting.request_confirmation_on_registrant_change_enabled - domain.registrant_verification_asked!(params, params[:registrar_id]) end end diff --git a/test/integration/repp/v1/domains/update_test.rb b/test/integration/repp/v1/domains/update_test.rb new file mode 100644 index 000000000..da79312d1 --- /dev/null +++ b/test/integration/repp/v1/domains/update_test.rb @@ -0,0 +1,85 @@ +require 'test_helper' + +class ReppV1DomainsCreateTest < ActionDispatch::IntegrationTest + def setup + @user = users(:api_bestnames) + @domain = domains(:shop) + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + token = "Basic #{token}" + + @auth_headers = { 'Authorization' => token } + end + + def test_updates_transfer_code_for_domain + @auth_headers['Content-Type'] = 'application/json' + new_auth_code = 'aisdcbkabcsdnc' + + payload = { + domain: { + auth_code: new_auth_code + } + } + + put "/repp/v1/domains/#{@domain.name}", headers: @auth_headers, params: payload.to_json + @domain.reload + json = JSON.parse(response.body, symbolize_names: true) + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + assert new_auth_code, @domain.auth_info + end + + def test_domain_pending_update_on_registrant_change + Setting.request_confirmation_on_registrant_change_enabled = true + + @auth_headers['Content-Type'] = 'application/json' + new_registrant = contacts(:william) + refute @domain.registrant == new_registrant + + payload = { + domain: { + registrant: { + code: new_registrant.code + } + } + } + + put "/repp/v1/domains/#{@domain.name}", headers: @auth_headers, params: payload.to_json + @domain.reload + json = JSON.parse(response.body, symbolize_names: true) + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + refute @domain.registrant.code == new_registrant.code + assert @domain.statuses.include? DomainStatus::PENDING_UPDATE + end + + def test_replaces_registrant_when_verified + Setting.request_confirmation_on_registrant_change_enabled = true + + @auth_headers['Content-Type'] = 'application/json' + new_registrant = contacts(:william) + refute @domain.registrant == new_registrant + + payload = { + domain: { + registrant: { + code: new_registrant.code, + verified: true + } + } + } + + put "/repp/v1/domains/#{@domain.name}", headers: @auth_headers, params: payload.to_json + @domain.reload + json = JSON.parse(response.body, symbolize_names: true) + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + assert @domain.registrant.code == new_registrant.code + refute @domain.statuses.include? DomainStatus::PENDING_UPDATE + end +end From 24c396251776d68f5c4ee04264f2832054f93aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 2 Feb 2021 11:55:09 +0200 Subject: [PATCH 51/80] REPP: Domain delete test --- app/controllers/repp/v1/domains_controller.rb | 8 +-- .../repp/v1/domains/delete_test.rb | 54 +++++++++++++++++++ .../repp/v1/domains/update_test.rb | 2 +- 3 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 test/integration/repp/v1/domains/delete_test.rb diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 3db71c23b..252375d88 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -178,7 +178,9 @@ module Repp @domain = Epp::Domain.find_by(registrar: registrar, name: params[:id]) @domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:id]) - @domain + return @domain if @domain + + raise ActiveRecord::RecordNotFound end def set_authorized_domain @@ -196,9 +198,9 @@ module Repp def domain_from_url_hash entry = transfer_info_params[:id] - return Domain.find(entry) if entry.match?(/\A[0-9]+\z/) + return Epp::Domain.find(entry) if entry.match?(/\A[0-9]+\z/) - Domain.find_by!('name = ? OR name_puny = ?', entry, entry) + Epp::Domain.find_by!('name = ? OR name_puny = ?', entry, entry) end def limit diff --git a/test/integration/repp/v1/domains/delete_test.rb b/test/integration/repp/v1/domains/delete_test.rb new file mode 100644 index 000000000..08b73e832 --- /dev/null +++ b/test/integration/repp/v1/domains/delete_test.rb @@ -0,0 +1,54 @@ +require 'test_helper' + +class ReppV1DomainsDeleteTest < ActionDispatch::IntegrationTest + def setup + @user = users(:api_bestnames) + @domain = domains(:shop) + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + token = "Basic #{token}" + + @auth_headers = { 'Authorization' => token } + end + + def test_domain_pending_delete_confirmation + Setting.request_confirmation_on_domain_deletion_enabled = true + @auth_headers['Content-Type'] = 'application/json' + + payload = { + delete: { + verified: false + } + } + + delete "/repp/v1/domains/#{@domain.name}", headers: @auth_headers, params: payload.to_json + @domain.reload + json = JSON.parse(response.body, symbolize_names: true) + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + assert @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE + end + + def test_domain_pending_delete_on_verified_delete + Setting.request_confirmation_on_domain_deletion_enabled = true + @auth_headers['Content-Type'] = 'application/json' + + payload = { + delete: { + verified: true + } + } + + delete "/repp/v1/domains/#{@domain.name}", headers: @auth_headers, params: payload.to_json + @domain.reload + json = JSON.parse(response.body, symbolize_names: true) + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + refute @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION + assert @domain.statuses.include? DomainStatus::PENDING_DELETE + end +end diff --git a/test/integration/repp/v1/domains/update_test.rb b/test/integration/repp/v1/domains/update_test.rb index da79312d1..d924fe7a3 100644 --- a/test/integration/repp/v1/domains/update_test.rb +++ b/test/integration/repp/v1/domains/update_test.rb @@ -1,6 +1,6 @@ require 'test_helper' -class ReppV1DomainsCreateTest < ActionDispatch::IntegrationTest +class ReppV1DomainsUpdateTest < ActionDispatch::IntegrationTest def setup @user = users(:api_bestnames) @domain = domains(:shop) From 312f19950457dd1e60793d3064a352e75d5d0050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 5 Feb 2021 12:53:51 +0200 Subject: [PATCH 52/80] REPP: Forward Registrar ID for domain update action --- app/controllers/repp/v1/domains_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 252375d88..8213f2bb2 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -4,7 +4,7 @@ module Repp class DomainsController < BaseController # rubocop:disable Metrics/ClassLength before_action :set_authorized_domain, only: %i[transfer_info destroy] before_action :validate_registrar_authorization, only: %i[transfer_info destroy] - before_action :forward_registrar_id, only: %i[create destroy] + before_action :forward_registrar_id, only: %i[create update destroy] before_action :set_domain, only: %i[show update] api :GET, '/repp/v1/domains' From d1bb6fcc608056d53764222c9498dcf2a2e6b8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 5 Feb 2021 16:22:54 +0200 Subject: [PATCH 53/80] REPP: Fix domain renew --- .../domains/check_balance/single_domain.rb | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/app/interactions/domains/check_balance/single_domain.rb b/app/interactions/domains/check_balance/single_domain.rb index 607913e92..d2a5862ca 100644 --- a/app/interactions/domains/check_balance/single_domain.rb +++ b/app/interactions/domains/check_balance/single_domain.rb @@ -9,16 +9,26 @@ module Domains string :unit def execute - return domain_pricelist.price.amount if domain_pricelist.try(:price) + if domain_pricelist.try(:price) + price = domain_pricelist.price.amount + return price if balance_ok?(price) + + domain.add_epp_error(2104, nil, nil, I18n.t(:billing_failure_credit_balance_low)) + errors.add(:domain, I18n.t(:billing_failure_credit_balance_low, domain: domain.name)) + else + domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) + errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain, domain: domain.name)) + end - domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) - errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain, - domain: domain.name)) false end private + def balance_ok?(price) + domain.registrar.cash_account.balance >= price + end + def domain_pricelist domain.pricelist(operation, period.try(:to_i), unit) end From bf4fa216bfb25b588e1fc886890be1090b939b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 5 Feb 2021 16:22:54 +0200 Subject: [PATCH 54/80] REPP: Fix domain renew --- .../domains/check_balance/single_domain.rb | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/app/interactions/domains/check_balance/single_domain.rb b/app/interactions/domains/check_balance/single_domain.rb index 607913e92..fbda791a1 100644 --- a/app/interactions/domains/check_balance/single_domain.rb +++ b/app/interactions/domains/check_balance/single_domain.rb @@ -9,16 +9,26 @@ module Domains string :unit def execute - return domain_pricelist.price.amount if domain_pricelist.try(:price) + if domain_pricelist.try(:price) + price = domain_pricelist.price.amount + return price if balance_ok?(price) + + domain.add_epp_error(2104, nil, nil, I18n.t(:not_enough_funds)) + errors.add(:domain, I18n.t(:billing_failure_credit_balance_low, domain: domain.name)) + else + domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) + errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain, domain: domain.name)) + end - domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) - errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain, - domain: domain.name)) false end private + def balance_ok?(price) + domain.registrar.cash_account.balance >= price + end + def domain_pricelist domain.pricelist(operation, period.try(:to_i), unit) end From 5db3b04aa745dee043cc5fb4cf7c90ff23b970f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 8 Feb 2021 11:54:02 +0200 Subject: [PATCH 55/80] Fix some CC issues --- app/interactions/domains/check_balance/single_domain.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/interactions/domains/check_balance/single_domain.rb b/app/interactions/domains/check_balance/single_domain.rb index fbda791a1..d9b1fbb24 100644 --- a/app/interactions/domains/check_balance/single_domain.rb +++ b/app/interactions/domains/check_balance/single_domain.rb @@ -17,7 +17,8 @@ module Domains errors.add(:domain, I18n.t(:billing_failure_credit_balance_low, domain: domain.name)) else domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) - errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain, domain: domain.name)) + errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain, + domain: domain.name)) end false From 115cefc0cf3c62ef32cab55654b490973866c80a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 8 Feb 2021 12:01:19 +0200 Subject: [PATCH 56/80] Fix some CC issues --- .../domains/check_balance/single_domain.rb | 11 +++++++---- test/integration/repp/v1/domains/bulk_renew_test.rb | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/interactions/domains/check_balance/single_domain.rb b/app/interactions/domains/check_balance/single_domain.rb index d9b1fbb24..411318d66 100644 --- a/app/interactions/domains/check_balance/single_domain.rb +++ b/app/interactions/domains/check_balance/single_domain.rb @@ -12,9 +12,6 @@ module Domains if domain_pricelist.try(:price) price = domain_pricelist.price.amount return price if balance_ok?(price) - - domain.add_epp_error(2104, nil, nil, I18n.t(:not_enough_funds)) - errors.add(:domain, I18n.t(:billing_failure_credit_balance_low, domain: domain.name)) else domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation)) errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain, @@ -27,7 +24,13 @@ module Domains private def balance_ok?(price) - domain.registrar.cash_account.balance >= price + if domain.registrar.cash_account.balance >= price + true + else + domain.add_epp_error(2104, nil, nil, I18n.t(:not_enough_funds)) + errors.add(:domain, I18n.t(:billing_failure_credit_balance_low, domain: domain.name)) + false + end end def domain_pricelist diff --git a/test/integration/repp/v1/domains/bulk_renew_test.rb b/test/integration/repp/v1/domains/bulk_renew_test.rb index 4cec91914..26a34dd39 100644 --- a/test/integration/repp/v1/domains/bulk_renew_test.rb +++ b/test/integration/repp/v1/domains/bulk_renew_test.rb @@ -69,7 +69,7 @@ class ReppV1DomainsBulkRenewTest < ActionDispatch::IntegrationTest assert_response :bad_request assert_equal 2002, json[:code] - assert_equal 'Not enough funds for renew domains', json[:message] + assert_equal 'Domain Billing failure - credit balance low', json[:message] end end From d7f01f24a28a559cef425cff3499074b617667e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 8 Feb 2021 14:10:57 +0200 Subject: [PATCH 57/80] Move actions to own namespace --- app/{models => }/actions/base_action.rb | 0 app/{models => }/actions/contact_create.rb | 2 +- app/{models => }/actions/contact_delete.rb | 2 +- app/{models => }/actions/contact_update.rb | 2 +- app/{models => }/actions/domain_create.rb | 2 +- app/{models => }/actions/domain_delete.rb | 2 +- app/{models => }/actions/domain_renew.rb | 0 app/{models => }/actions/domain_transfer.rb | 0 app/{models => }/actions/domain_update.rb | 2 +- app/controllers/epp/contacts_controller.rb | 6 +++--- app/controllers/epp/domains_controller.rb | 8 ++++---- app/controllers/repp/v1/contacts_controller.rb | 6 +++--- app/controllers/repp/v1/domains/contacts_controller.rb | 2 +- app/controllers/repp/v1/domains/dnssec_controller.rb | 2 +- app/controllers/repp/v1/domains/nameservers_controller.rb | 4 ++-- app/controllers/repp/v1/domains/transfers_controller.rb | 2 +- app/controllers/repp/v1/domains_controller.rb | 8 ++++---- .../domains/update_confirm/process_update_confirmed.rb | 2 +- config/application.rb | 1 + 19 files changed, 27 insertions(+), 26 deletions(-) rename app/{models => }/actions/base_action.rb (100%) rename app/{models => }/actions/contact_create.rb (95%) rename app/{models => }/actions/contact_delete.rb (87%) rename app/{models => }/actions/contact_update.rb (97%) rename app/{models => }/actions/domain_create.rb (98%) rename app/{models => }/actions/domain_delete.rb (92%) rename app/{models => }/actions/domain_renew.rb (100%) rename app/{models => }/actions/domain_transfer.rb (100%) rename app/{models => }/actions/domain_update.rb (98%) diff --git a/app/models/actions/base_action.rb b/app/actions/base_action.rb similarity index 100% rename from app/models/actions/base_action.rb rename to app/actions/base_action.rb diff --git a/app/models/actions/contact_create.rb b/app/actions/contact_create.rb similarity index 95% rename from app/models/actions/contact_create.rb rename to app/actions/contact_create.rb index 9c700f858..8c6cb2282 100644 --- a/app/models/actions/contact_create.rb +++ b/app/actions/contact_create.rb @@ -59,7 +59,7 @@ module Actions end def maybe_attach_legal_doc - Actions::BaseAction.attach_legal_doc_to_new(contact, legal_document, domain: false) + ::Actions::BaseAction.attach_legal_doc_to_new(contact, legal_document, domain: false) end def commit diff --git a/app/models/actions/contact_delete.rb b/app/actions/contact_delete.rb similarity index 87% rename from app/models/actions/contact_delete.rb rename to app/actions/contact_delete.rb index 2923b7de0..27b131756 100644 --- a/app/models/actions/contact_delete.rb +++ b/app/actions/contact_delete.rb @@ -23,7 +23,7 @@ module Actions end def maybe_attach_legal_doc - Actions::BaseAction.maybe_attach_legal_doc(contact, legal_document) + ::Actions::BaseAction.maybe_attach_legal_doc(contact, legal_document) end def commit diff --git a/app/models/actions/contact_update.rb b/app/actions/contact_update.rb similarity index 97% rename from app/models/actions/contact_update.rb rename to app/actions/contact_update.rb index cba8fad51..e96ea8afb 100644 --- a/app/models/actions/contact_update.rb +++ b/app/actions/contact_update.rb @@ -42,7 +42,7 @@ module Actions end def maybe_attach_legal_doc - Actions::BaseAction.maybe_attach_legal_doc(contact, legal_document) + ::Actions::BaseAction.maybe_attach_legal_doc(contact, legal_document) end def maybe_update_ident diff --git a/app/models/actions/domain_create.rb b/app/actions/domain_create.rb similarity index 98% rename from app/models/actions/domain_create.rb rename to app/actions/domain_create.rb index 4e148ab3e..9c2dfba56 100644 --- a/app/models/actions/domain_create.rb +++ b/app/actions/domain_create.rb @@ -178,7 +178,7 @@ module Actions end def maybe_attach_legal_doc - Actions::BaseAction.attach_legal_doc_to_new(domain, params[:legal_document], domain: true) + ::Actions::BaseAction.attach_legal_doc_to_new(domain, params[:legal_document], domain: true) end def process_auction_and_disputes diff --git a/app/models/actions/domain_delete.rb b/app/actions/domain_delete.rb similarity index 92% rename from app/models/actions/domain_delete.rb rename to app/actions/domain_delete.rb index 929b1f6f7..cb6cfa5d7 100644 --- a/app/models/actions/domain_delete.rb +++ b/app/actions/domain_delete.rb @@ -23,7 +23,7 @@ module Actions end def maybe_attach_legal_doc - Actions::BaseAction.attach_legal_doc_to_new(domain, params[:legal_document], domain: true) + ::Actions::BaseAction.attach_legal_doc_to_new(domain, params[:legal_document], domain: true) end def verify_not_discarded diff --git a/app/models/actions/domain_renew.rb b/app/actions/domain_renew.rb similarity index 100% rename from app/models/actions/domain_renew.rb rename to app/actions/domain_renew.rb diff --git a/app/models/actions/domain_transfer.rb b/app/actions/domain_transfer.rb similarity index 100% rename from app/models/actions/domain_transfer.rb rename to app/actions/domain_transfer.rb diff --git a/app/models/actions/domain_update.rb b/app/actions/domain_update.rb similarity index 98% rename from app/models/actions/domain_update.rb rename to app/actions/domain_update.rb index 0e2349832..60b8b59cc 100644 --- a/app/models/actions/domain_update.rb +++ b/app/actions/domain_update.rb @@ -14,7 +14,7 @@ module Actions assign_new_registrant if params[:registrant] assign_relational_modifications assign_requested_statuses - Actions::BaseAction.maybe_attach_legal_doc(domain, params[:legal_document]) + ::Actions::BaseAction.maybe_attach_legal_doc(domain, params[:legal_document]) commit end diff --git a/app/controllers/epp/contacts_controller.rb b/app/controllers/epp/contacts_controller.rb index 85305213b..28559e3b7 100644 --- a/app/controllers/epp/contacts_controller.rb +++ b/app/controllers/epp/contacts_controller.rb @@ -23,7 +23,7 @@ module Epp @contact = Epp::Contact.new(params[:parsed_frame], current_user.registrar) collected_data = ::Deserializers::Xml::ContactCreate.new(params[:parsed_frame]) - action = Actions::ContactCreate.new(@contact, collected_data.legal_document, + action = ::Actions::ContactCreate.new(@contact, collected_data.legal_document, collected_data.ident) action_call_response(action: action) @@ -33,7 +33,7 @@ module Epp authorize! :update, @contact, @password collected_data = ::Deserializers::Xml::ContactUpdate.new(params[:parsed_frame]) - action = Actions::ContactUpdate.new(@contact, + action = ::Actions::ContactUpdate.new(@contact, collected_data.contact, collected_data.legal_document, collected_data.ident, @@ -44,7 +44,7 @@ module Epp def delete authorize! :delete, @contact, @password - action = Actions::ContactDelete.new(@contact, params[:legal_document]) + action = ::Actions::ContactDelete.new(@contact, params[:legal_document]) unless action.call handle_errors(@contact) return diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index 80b7d8843..c3ea3ac4a 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -32,7 +32,7 @@ module Epp registrar_id = current_user.registrar.id @domain = Epp::Domain.new data = ::Deserializers::Xml::DomainCreate.new(params[:parsed_frame], registrar_id).call - action = Actions::DomainCreate.new(@domain, data) + action = ::Actions::DomainCreate.new(@domain, data) action.call ? render_epp_response('/epp/domains/create') : handle_errors(@domain) end @@ -43,7 +43,7 @@ module Epp registrar_id = current_user.registrar.id update_params = ::Deserializers::Xml::DomainUpdate.new(params[:parsed_frame], registrar_id).call - action = Actions::DomainUpdate.new(@domain, update_params, false) + action = ::Actions::DomainUpdate.new(@domain, update_params, false) (handle_errors(@domain) and return) unless action.call pending = @domain.epp_pending_update.present? @@ -54,7 +54,7 @@ module Epp authorize!(:delete, @domain, @password) frame = params[:parsed_frame] delete_params = ::Deserializers::Xml::DomainDelete.new(frame).call - action = Actions::DomainDelete.new(@domain, delete_params, current_user.registrar) + action = ::Actions::DomainDelete.new(@domain, delete_params, current_user.registrar) (handle_errors(@domain) and return) unless action.call @@ -77,7 +77,7 @@ module Epp registrar_id = current_user.registrar.id renew_params = ::Deserializers::Xml::Domain.new(params[:parsed_frame], registrar_id).call - action = Actions::DomainRenew.new(@domain, renew_params, current_user.registrar) + action = ::Actions::DomainRenew.new(@domain, renew_params, current_user.registrar) if action.call render_epp_response '/epp/domains/renew' else diff --git a/app/controllers/repp/v1/contacts_controller.rb b/app/controllers/repp/v1/contacts_controller.rb index 92f89a160..6298bbbb3 100644 --- a/app/controllers/repp/v1/contacts_controller.rb +++ b/app/controllers/repp/v1/contacts_controller.rb @@ -35,7 +35,7 @@ module Repp desc 'Create a new contact' def create @contact = Epp::Contact.new(contact_params_with_address, current_user.registrar, epp: false) - action = Actions::ContactCreate.new(@contact, params[:legal_document], + action = ::Actions::ContactCreate.new(@contact, params[:legal_document], contact_ident_params) unless action.call @@ -49,7 +49,7 @@ module Repp api :PUT, '/repp/v1/contacts/:contact_code' desc 'Update existing contact' def update - action = Actions::ContactUpdate.new(@contact, contact_params_with_address(required: false), + action = ::Actions::ContactUpdate.new(@contact, contact_params_with_address(required: false), params[:legal_document], contact_ident_params(required: false), current_user) @@ -64,7 +64,7 @@ module Repp api :DELETE, '/repp/v1/contacts/:contact_code' desc 'Delete a specific contact' def destroy - action = Actions::ContactDelete.new(@contact, params[:legal_document]) + action = ::Actions::ContactDelete.new(@contact, params[:legal_document]) unless action.call handle_errors(@contact) return diff --git a/app/controllers/repp/v1/domains/contacts_controller.rb b/app/controllers/repp/v1/domains/contacts_controller.rb index f2e5e4018..35690a8c3 100644 --- a/app/controllers/repp/v1/domains/contacts_controller.rb +++ b/app/controllers/repp/v1/domains/contacts_controller.rb @@ -39,7 +39,7 @@ module Repp def cta(action = 'add') params[:contacts].each { |c| c[:action] = action } - action = Actions::DomainUpdate.new(@domain, contact_create_params, false) + action = ::Actions::DomainUpdate.new(@domain, contact_create_params, false) # rubocop:disable Style/AndOr handle_errors(@domain) and return unless action.call diff --git a/app/controllers/repp/v1/domains/dnssec_controller.rb b/app/controllers/repp/v1/domains/dnssec_controller.rb index fcfaa991a..4100a3bc9 100644 --- a/app/controllers/repp/v1/domains/dnssec_controller.rb +++ b/app/controllers/repp/v1/domains/dnssec_controller.rb @@ -38,7 +38,7 @@ module Repp def cta(action = 'add') params[:dns_keys].each { |n| n[:action] = action } - action = Actions::DomainUpdate.new(@domain, dnssec_params, false) + action = ::Actions::DomainUpdate.new(@domain, dnssec_params, false) # rubocop:disable Style/AndOr (handle_errors(@domain) and return) unless action.call diff --git a/app/controllers/repp/v1/domains/nameservers_controller.rb b/app/controllers/repp/v1/domains/nameservers_controller.rb index fe38de93c..1bf053477 100644 --- a/app/controllers/repp/v1/domains/nameservers_controller.rb +++ b/app/controllers/repp/v1/domains/nameservers_controller.rb @@ -14,7 +14,7 @@ module Repp end def create params[:nameservers].each { |n| n[:action] = 'add' } - action = Actions::DomainUpdate.new(@domain, nameserver_params, current_user) + action = ::Actions::DomainUpdate.new(@domain, nameserver_params, current_user) unless action.call handle_errors(@domain) @@ -28,7 +28,7 @@ module Repp desc 'Delete specific nameserver from domain' def destroy nameserver = { nameservers: [{ hostname: params[:id], action: 'rem' }] } - action = Actions::DomainUpdate.new(@domain, nameserver, false) + action = ::Actions::DomainUpdate.new(@domain, nameserver, false) unless action.call handle_errors(@domain) diff --git a/app/controllers/repp/v1/domains/transfers_controller.rb b/app/controllers/repp/v1/domains/transfers_controller.rb index e9474d94d..c4ece6aa4 100644 --- a/app/controllers/repp/v1/domains/transfers_controller.rb +++ b/app/controllers/repp/v1/domains/transfers_controller.rb @@ -10,7 +10,7 @@ module Repp param :transfer_code, String, required: true, desc: 'Renew period. Month (m) or year (y)' end def create - action = Actions::DomainTransfer.new(@domain, transfer_params[:transfer][:transfer_code], + action = ::Actions::DomainTransfer.new(@domain, transfer_params[:transfer][:transfer_code], current_user.registrar) unless action.call diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 8213f2bb2..a402981fa 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -55,7 +55,7 @@ module Repp def create authorize!(:create, Epp::Domain) @domain = Epp::Domain.new - action = Actions::DomainCreate.new(@domain, domain_create_params) + action = ::Actions::DomainCreate.new(@domain, domain_create_params) # rubocop:disable Style/AndOr handle_errors(@domain) and return unless action.call @@ -76,7 +76,7 @@ module Repp param :auth_info, String, required: false, desc: 'New authorization code' end def update - action = Actions::DomainUpdate.new(@domain, params[:domain], false) + action = ::Actions::DomainUpdate.new(@domain, params[:domain], false) unless action.call handle_errors(@domain) @@ -122,7 +122,7 @@ module Repp desc: 'Whether to ask registrant verification or not' end def destroy - action = Actions::DomainDelete.new(@domain, params, current_user.registrar) + action = ::Actions::DomainDelete.new(@domain, params, current_user.registrar) # rubocop:disable Style/AndOr handle_errors(@domain) and return unless action.call @@ -141,7 +141,7 @@ module Repp def initiate_transfer(transfer) domain = Epp::Domain.find_or_initialize_by(name: transfer[:domain_name]) - action = Actions::DomainTransfer.new(domain, transfer[:transfer_code], + action = ::Actions::DomainTransfer.new(domain, transfer[:transfer_code], current_user.registrar) if action.call diff --git a/app/interactions/domains/update_confirm/process_update_confirmed.rb b/app/interactions/domains/update_confirm/process_update_confirmed.rb index 291253651..d12f479d2 100644 --- a/app/interactions/domains/update_confirm/process_update_confirmed.rb +++ b/app/interactions/domains/update_confirm/process_update_confirmed.rb @@ -25,7 +25,7 @@ module Domains frame = frame_json ? frame_json.with_indifferent_access : {} assign_domain_update_meta - Actions::DomainUpdate.new(domain, frame, true).call + ::Actions::DomainUpdate.new(domain, frame, true).call end def assign_domain_update_meta diff --git a/config/application.rb b/config/application.rb index 014c03269..22c2c4df9 100644 --- a/config/application.rb +++ b/config/application.rb @@ -38,6 +38,7 @@ module DomainNameRegistry config.autoload_paths += Dir[Rails.root.join('app', 'models', '**/')] config.autoload_paths += Dir[Rails.root.join('app', 'lib', '**/')] config.autoload_paths += Dir[Rails.root.join('app', 'interactions', '**/')] + config.autoload_paths += Dir[Rails.root.join('app', 'actions', '**/')] config.eager_load_paths << config.root.join('lib', 'validators') config.eager_load_paths << config.root.join('app', 'lib') config.watchable_dirs['lib'] = %i[rb] From fdef27c45e9ac77c1b1c661263aadce676d893d5 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 8 Feb 2021 17:44:15 +0500 Subject: [PATCH 58/80] Mode all the actions to Interactions folder --- app/controllers/epp/contacts_controller.rb | 6 +++--- app/controllers/epp/domains_controller.rb | 8 ++++---- app/controllers/repp/v1/contacts_controller.rb | 6 +++--- app/controllers/repp/v1/domains/contacts_controller.rb | 2 +- app/controllers/repp/v1/domains/dnssec_controller.rb | 2 +- app/controllers/repp/v1/domains/nameservers_controller.rb | 4 ++-- app/controllers/repp/v1/domains/transfers_controller.rb | 2 +- app/controllers/repp/v1/domains_controller.rb | 8 ++++---- app/{ => interactions}/actions/base_action.rb | 0 app/{ => interactions}/actions/contact_create.rb | 0 app/{ => interactions}/actions/contact_delete.rb | 0 app/{ => interactions}/actions/contact_update.rb | 0 app/{ => interactions}/actions/domain_create.rb | 0 app/{ => interactions}/actions/domain_delete.rb | 0 app/{ => interactions}/actions/domain_renew.rb | 0 app/{ => interactions}/actions/domain_transfer.rb | 0 app/{ => interactions}/actions/domain_update.rb | 0 .../domains/update_confirm/process_update_confirmed.rb | 2 +- 18 files changed, 20 insertions(+), 20 deletions(-) rename app/{ => interactions}/actions/base_action.rb (100%) rename app/{ => interactions}/actions/contact_create.rb (100%) rename app/{ => interactions}/actions/contact_delete.rb (100%) rename app/{ => interactions}/actions/contact_update.rb (100%) rename app/{ => interactions}/actions/domain_create.rb (100%) rename app/{ => interactions}/actions/domain_delete.rb (100%) rename app/{ => interactions}/actions/domain_renew.rb (100%) rename app/{ => interactions}/actions/domain_transfer.rb (100%) rename app/{ => interactions}/actions/domain_update.rb (100%) diff --git a/app/controllers/epp/contacts_controller.rb b/app/controllers/epp/contacts_controller.rb index 28559e3b7..85305213b 100644 --- a/app/controllers/epp/contacts_controller.rb +++ b/app/controllers/epp/contacts_controller.rb @@ -23,7 +23,7 @@ module Epp @contact = Epp::Contact.new(params[:parsed_frame], current_user.registrar) collected_data = ::Deserializers::Xml::ContactCreate.new(params[:parsed_frame]) - action = ::Actions::ContactCreate.new(@contact, collected_data.legal_document, + action = Actions::ContactCreate.new(@contact, collected_data.legal_document, collected_data.ident) action_call_response(action: action) @@ -33,7 +33,7 @@ module Epp authorize! :update, @contact, @password collected_data = ::Deserializers::Xml::ContactUpdate.new(params[:parsed_frame]) - action = ::Actions::ContactUpdate.new(@contact, + action = Actions::ContactUpdate.new(@contact, collected_data.contact, collected_data.legal_document, collected_data.ident, @@ -44,7 +44,7 @@ module Epp def delete authorize! :delete, @contact, @password - action = ::Actions::ContactDelete.new(@contact, params[:legal_document]) + action = Actions::ContactDelete.new(@contact, params[:legal_document]) unless action.call handle_errors(@contact) return diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index c3ea3ac4a..80b7d8843 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -32,7 +32,7 @@ module Epp registrar_id = current_user.registrar.id @domain = Epp::Domain.new data = ::Deserializers::Xml::DomainCreate.new(params[:parsed_frame], registrar_id).call - action = ::Actions::DomainCreate.new(@domain, data) + action = Actions::DomainCreate.new(@domain, data) action.call ? render_epp_response('/epp/domains/create') : handle_errors(@domain) end @@ -43,7 +43,7 @@ module Epp registrar_id = current_user.registrar.id update_params = ::Deserializers::Xml::DomainUpdate.new(params[:parsed_frame], registrar_id).call - action = ::Actions::DomainUpdate.new(@domain, update_params, false) + action = Actions::DomainUpdate.new(@domain, update_params, false) (handle_errors(@domain) and return) unless action.call pending = @domain.epp_pending_update.present? @@ -54,7 +54,7 @@ module Epp authorize!(:delete, @domain, @password) frame = params[:parsed_frame] delete_params = ::Deserializers::Xml::DomainDelete.new(frame).call - action = ::Actions::DomainDelete.new(@domain, delete_params, current_user.registrar) + action = Actions::DomainDelete.new(@domain, delete_params, current_user.registrar) (handle_errors(@domain) and return) unless action.call @@ -77,7 +77,7 @@ module Epp registrar_id = current_user.registrar.id renew_params = ::Deserializers::Xml::Domain.new(params[:parsed_frame], registrar_id).call - action = ::Actions::DomainRenew.new(@domain, renew_params, current_user.registrar) + action = Actions::DomainRenew.new(@domain, renew_params, current_user.registrar) if action.call render_epp_response '/epp/domains/renew' else diff --git a/app/controllers/repp/v1/contacts_controller.rb b/app/controllers/repp/v1/contacts_controller.rb index 6298bbbb3..92f89a160 100644 --- a/app/controllers/repp/v1/contacts_controller.rb +++ b/app/controllers/repp/v1/contacts_controller.rb @@ -35,7 +35,7 @@ module Repp desc 'Create a new contact' def create @contact = Epp::Contact.new(contact_params_with_address, current_user.registrar, epp: false) - action = ::Actions::ContactCreate.new(@contact, params[:legal_document], + action = Actions::ContactCreate.new(@contact, params[:legal_document], contact_ident_params) unless action.call @@ -49,7 +49,7 @@ module Repp api :PUT, '/repp/v1/contacts/:contact_code' desc 'Update existing contact' def update - action = ::Actions::ContactUpdate.new(@contact, contact_params_with_address(required: false), + action = Actions::ContactUpdate.new(@contact, contact_params_with_address(required: false), params[:legal_document], contact_ident_params(required: false), current_user) @@ -64,7 +64,7 @@ module Repp api :DELETE, '/repp/v1/contacts/:contact_code' desc 'Delete a specific contact' def destroy - action = ::Actions::ContactDelete.new(@contact, params[:legal_document]) + action = Actions::ContactDelete.new(@contact, params[:legal_document]) unless action.call handle_errors(@contact) return diff --git a/app/controllers/repp/v1/domains/contacts_controller.rb b/app/controllers/repp/v1/domains/contacts_controller.rb index 35690a8c3..f2e5e4018 100644 --- a/app/controllers/repp/v1/domains/contacts_controller.rb +++ b/app/controllers/repp/v1/domains/contacts_controller.rb @@ -39,7 +39,7 @@ module Repp def cta(action = 'add') params[:contacts].each { |c| c[:action] = action } - action = ::Actions::DomainUpdate.new(@domain, contact_create_params, false) + action = Actions::DomainUpdate.new(@domain, contact_create_params, false) # rubocop:disable Style/AndOr handle_errors(@domain) and return unless action.call diff --git a/app/controllers/repp/v1/domains/dnssec_controller.rb b/app/controllers/repp/v1/domains/dnssec_controller.rb index 4100a3bc9..fcfaa991a 100644 --- a/app/controllers/repp/v1/domains/dnssec_controller.rb +++ b/app/controllers/repp/v1/domains/dnssec_controller.rb @@ -38,7 +38,7 @@ module Repp def cta(action = 'add') params[:dns_keys].each { |n| n[:action] = action } - action = ::Actions::DomainUpdate.new(@domain, dnssec_params, false) + action = Actions::DomainUpdate.new(@domain, dnssec_params, false) # rubocop:disable Style/AndOr (handle_errors(@domain) and return) unless action.call diff --git a/app/controllers/repp/v1/domains/nameservers_controller.rb b/app/controllers/repp/v1/domains/nameservers_controller.rb index 1bf053477..fe38de93c 100644 --- a/app/controllers/repp/v1/domains/nameservers_controller.rb +++ b/app/controllers/repp/v1/domains/nameservers_controller.rb @@ -14,7 +14,7 @@ module Repp end def create params[:nameservers].each { |n| n[:action] = 'add' } - action = ::Actions::DomainUpdate.new(@domain, nameserver_params, current_user) + action = Actions::DomainUpdate.new(@domain, nameserver_params, current_user) unless action.call handle_errors(@domain) @@ -28,7 +28,7 @@ module Repp desc 'Delete specific nameserver from domain' def destroy nameserver = { nameservers: [{ hostname: params[:id], action: 'rem' }] } - action = ::Actions::DomainUpdate.new(@domain, nameserver, false) + action = Actions::DomainUpdate.new(@domain, nameserver, false) unless action.call handle_errors(@domain) diff --git a/app/controllers/repp/v1/domains/transfers_controller.rb b/app/controllers/repp/v1/domains/transfers_controller.rb index c4ece6aa4..e9474d94d 100644 --- a/app/controllers/repp/v1/domains/transfers_controller.rb +++ b/app/controllers/repp/v1/domains/transfers_controller.rb @@ -10,7 +10,7 @@ module Repp param :transfer_code, String, required: true, desc: 'Renew period. Month (m) or year (y)' end def create - action = ::Actions::DomainTransfer.new(@domain, transfer_params[:transfer][:transfer_code], + action = Actions::DomainTransfer.new(@domain, transfer_params[:transfer][:transfer_code], current_user.registrar) unless action.call diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index a402981fa..8213f2bb2 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -55,7 +55,7 @@ module Repp def create authorize!(:create, Epp::Domain) @domain = Epp::Domain.new - action = ::Actions::DomainCreate.new(@domain, domain_create_params) + action = Actions::DomainCreate.new(@domain, domain_create_params) # rubocop:disable Style/AndOr handle_errors(@domain) and return unless action.call @@ -76,7 +76,7 @@ module Repp param :auth_info, String, required: false, desc: 'New authorization code' end def update - action = ::Actions::DomainUpdate.new(@domain, params[:domain], false) + action = Actions::DomainUpdate.new(@domain, params[:domain], false) unless action.call handle_errors(@domain) @@ -122,7 +122,7 @@ module Repp desc: 'Whether to ask registrant verification or not' end def destroy - action = ::Actions::DomainDelete.new(@domain, params, current_user.registrar) + action = Actions::DomainDelete.new(@domain, params, current_user.registrar) # rubocop:disable Style/AndOr handle_errors(@domain) and return unless action.call @@ -141,7 +141,7 @@ module Repp def initiate_transfer(transfer) domain = Epp::Domain.find_or_initialize_by(name: transfer[:domain_name]) - action = ::Actions::DomainTransfer.new(domain, transfer[:transfer_code], + action = Actions::DomainTransfer.new(domain, transfer[:transfer_code], current_user.registrar) if action.call diff --git a/app/actions/base_action.rb b/app/interactions/actions/base_action.rb similarity index 100% rename from app/actions/base_action.rb rename to app/interactions/actions/base_action.rb diff --git a/app/actions/contact_create.rb b/app/interactions/actions/contact_create.rb similarity index 100% rename from app/actions/contact_create.rb rename to app/interactions/actions/contact_create.rb diff --git a/app/actions/contact_delete.rb b/app/interactions/actions/contact_delete.rb similarity index 100% rename from app/actions/contact_delete.rb rename to app/interactions/actions/contact_delete.rb diff --git a/app/actions/contact_update.rb b/app/interactions/actions/contact_update.rb similarity index 100% rename from app/actions/contact_update.rb rename to app/interactions/actions/contact_update.rb diff --git a/app/actions/domain_create.rb b/app/interactions/actions/domain_create.rb similarity index 100% rename from app/actions/domain_create.rb rename to app/interactions/actions/domain_create.rb diff --git a/app/actions/domain_delete.rb b/app/interactions/actions/domain_delete.rb similarity index 100% rename from app/actions/domain_delete.rb rename to app/interactions/actions/domain_delete.rb diff --git a/app/actions/domain_renew.rb b/app/interactions/actions/domain_renew.rb similarity index 100% rename from app/actions/domain_renew.rb rename to app/interactions/actions/domain_renew.rb diff --git a/app/actions/domain_transfer.rb b/app/interactions/actions/domain_transfer.rb similarity index 100% rename from app/actions/domain_transfer.rb rename to app/interactions/actions/domain_transfer.rb diff --git a/app/actions/domain_update.rb b/app/interactions/actions/domain_update.rb similarity index 100% rename from app/actions/domain_update.rb rename to app/interactions/actions/domain_update.rb diff --git a/app/interactions/domains/update_confirm/process_update_confirmed.rb b/app/interactions/domains/update_confirm/process_update_confirmed.rb index d12f479d2..291253651 100644 --- a/app/interactions/domains/update_confirm/process_update_confirmed.rb +++ b/app/interactions/domains/update_confirm/process_update_confirmed.rb @@ -25,7 +25,7 @@ module Domains frame = frame_json ? frame_json.with_indifferent_access : {} assign_domain_update_meta - ::Actions::DomainUpdate.new(domain, frame, true).call + Actions::DomainUpdate.new(domain, frame, true).call end def assign_domain_update_meta From aedfeac45986089d3913a71bcc42b4fef3c5c40f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 11 Feb 2021 11:23:13 +0200 Subject: [PATCH 59/80] Attempt to fix renew issues --- app/interactions/domains/bulk_renew/single_domain_renew.rb | 1 + app/models/billing/price.rb | 3 +++ 2 files changed, 4 insertions(+) diff --git a/app/interactions/domains/bulk_renew/single_domain_renew.rb b/app/interactions/domains/bulk_renew/single_domain_renew.rb index bcfc5b451..5951ef9ec 100644 --- a/app/interactions/domains/bulk_renew/single_domain_renew.rb +++ b/app/interactions/domains/bulk_renew/single_domain_renew.rb @@ -56,6 +56,7 @@ module Domains private def add_error + domain.add_epp_error(2104, nil, nil, I18n.t(:domain_renew_error_for_domain)) errors.add(:domain, I18n.t('domain_renew_error_for_domain', domain: domain.name)) end end diff --git a/app/models/billing/price.rb b/app/models/billing/price.rb index dac458b00..642cac17c 100644 --- a/app/models/billing/price.rb +++ b/app/models/billing/price.rb @@ -60,7 +60,10 @@ module Billing def self.price_for(zone, operation_category, duration) lists = valid.where(zone: zone, operation_category: operation_category, duration: duration) return lists.first if lists.count == 1 + lists.order(valid_from: :desc).first + rescue ActiveRecord::StatementInvalid + nil end def name From 9d57f347cb2e78b25e0624ebf7848ac29826775c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 11 Feb 2021 11:43:38 +0200 Subject: [PATCH 60/80] Reject registrant change if serverRegistrantUpdateProhibited --- app/interactions/actions/domain_update.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/interactions/actions/domain_update.rb b/app/interactions/actions/domain_update.rb index 60b8b59cc..6bc4894ae 100644 --- a/app/interactions/actions/domain_update.rb +++ b/app/interactions/actions/domain_update.rb @@ -60,7 +60,12 @@ module Actions return if domain.registrant == new_registrant @changes_registrant = true if domain.registrant.ident != new_registrant.ident - domain.registrant = new_registrant + if @changes_registrant && domain.registrant_change_prohibited? + domain.add_epp_error(2304, "status", DomainStatus::SERVER_REGISTRANT_CHANGE_PROHIBITED, + I18n.t(:object_status_prohibits_operation)) + else + domain.registrant = new_registrant + end end def assign_nameserver_modifications From a03ac4ff8289e8b53d4ab91df3d7cbeb53cd1c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 11 Feb 2021 11:48:08 +0200 Subject: [PATCH 61/80] Fix CC issues --- app/interactions/actions/domain_update.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/interactions/actions/domain_update.rb b/app/interactions/actions/domain_update.rb index 6bc4894ae..e93162fd5 100644 --- a/app/interactions/actions/domain_update.rb +++ b/app/interactions/actions/domain_update.rb @@ -61,7 +61,7 @@ module Actions @changes_registrant = true if domain.registrant.ident != new_registrant.ident if @changes_registrant && domain.registrant_change_prohibited? - domain.add_epp_error(2304, "status", DomainStatus::SERVER_REGISTRANT_CHANGE_PROHIBITED, + domain.add_epp_error(2304, 'status', DomainStatus::SERVER_REGISTRANT_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation)) else domain.registrant = new_registrant From 44226aa5d6f257aa6f123b57c9fea28dcd3786eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 11 Feb 2021 12:37:39 +0200 Subject: [PATCH 62/80] Fix domain renew erros --- app/models/epp/domain.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index cd17ba5dc..143cfcc99 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -208,7 +208,7 @@ class Epp::Domain < Domain end def add_renew_epp_errors - if renew_blocking_statuses.any? && !renewable? + if renew_blocking_statuses.any? || !renewable? add_epp_error('2304', 'status', renew_blocking_statuses, I18n.t('object_status_prohibits_operation')) end From 5693d0dd74fbc98accb418f2fb483da9e6a04d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 11 Feb 2021 15:08:26 +0200 Subject: [PATCH 63/80] Tech replace: Skip if domain has update prohibited --- app/models/domain.rb | 2 +- app/models/tech_domain_contact.rb | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/models/domain.rb b/app/models/domain.rb index 53f0fa5b6..a11f50f40 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -492,7 +492,7 @@ class Domain < ApplicationRecord # depricated not used, not valid def update_prohibited? - pending_update_prohibited? && pending_delete_prohibited? + (statuses & DomainStatus::UPDATE_PROHIBIT_STATES).present? end # public api diff --git a/app/models/tech_domain_contact.rb b/app/models/tech_domain_contact.rb index 20f21b6ed..eff815350 100644 --- a/app/models/tech_domain_contact.rb +++ b/app/models/tech_domain_contact.rb @@ -6,7 +6,7 @@ class TechDomainContact < DomainContact tech_contacts = where(contact: current_contact) tech_contacts.each do |tech_contact| - if tech_contact.domain.bulk_update_prohibited? + if irreplaceable?(tech_contact) skipped_domains << tech_contact.domain.name next end @@ -20,4 +20,9 @@ class TechDomainContact < DomainContact end [affected_domains.sort, skipped_domains.sort] end + + def self.irreplaceable?(tech_contact) + dn = tech_contact.domain + dn.bulk_update_prohibited? || dn.update_prohibited? || dn.tech_change_prohibited? + end end From 6045cd4e566e9aa2a90146faab3d0dffed608a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 12 Feb 2021 10:14:56 +0200 Subject: [PATCH 64/80] Fix domain delete functionality --- app/interactions/actions/domain_delete.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/interactions/actions/domain_delete.rb b/app/interactions/actions/domain_delete.rb index cb6cfa5d7..d7fd3496a 100644 --- a/app/interactions/actions/domain_delete.rb +++ b/app/interactions/actions/domain_delete.rb @@ -51,10 +51,6 @@ module Actions else domain.set_pending_delete! end - - return false if domain.errors.any? - return false if domain.errors[:epp_errors].any? - true end end From 4ed4e36fa1d95491374d801852688a6896c5b7a4 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Mon, 15 Feb 2021 12:18:11 +0200 Subject: [PATCH 65/80] added test when ipv4 and ipv6 isnt in array for bulk nameservers changed --- .../admin_area/domain_update_confirms_test.rb | 80 +++++++++++++++++++ .../repp/v1/registrar/nameservers_test.rb | 46 +++++++++++ 2 files changed, 126 insertions(+) create mode 100644 test/integration/admin_area/domain_update_confirms_test.rb diff --git a/test/integration/admin_area/domain_update_confirms_test.rb b/test/integration/admin_area/domain_update_confirms_test.rb new file mode 100644 index 000000000..9eb79685f --- /dev/null +++ b/test/integration/admin_area/domain_update_confirms_test.rb @@ -0,0 +1,80 @@ +require 'test_helper' +require 'application_system_test_case' + +class AdminAreaBlockedDomainsIntegrationTest < JavaScriptApplicationSystemTestCase + setup do + WebMock.allow_net_connect! + sign_in users(:admin) + @domain = domains(:shop) + end + + def test_t + new_registrant = contacts(:william) + assert_not_equal new_registrant, @domain.registrant + + puts new_registrant.name + request_xml = <<-XML + + + + + + #{@domain.name} + + #{new_registrant.code} + + + + + + #{'test' * 2000} + + + + + XML + + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + @domain.reload + + puts @domain.registrant + end + + private + + def update_registrant_of_domain + new_registrant = contacts(:william) + assert_not_equal new_registrant, @domain.registrant + + @domain.registrant + request_xml = <<-XML + + + + + + #{@domain.name} + + #{new_registrant.code} + + + + + + #{'test' * 2000} + + + + + XML + + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + @domain.reload + + # puts response.body + puts @domain.registrant + end + +end \ No newline at end of file diff --git a/test/integration/repp/v1/registrar/nameservers_test.rb b/test/integration/repp/v1/registrar/nameservers_test.rb index f01769dfb..0e527da98 100644 --- a/test/integration/repp/v1/registrar/nameservers_test.rb +++ b/test/integration/repp/v1/registrar/nameservers_test.rb @@ -74,4 +74,50 @@ class ReppV1RegistrarNameserversTest < ActionDispatch::IntegrationTest assert_equal 2005, json[:code] assert_equal 'IPv6 is invalid [ipv6]', json[:message] end + + def test_ipv4_isnt_array + nameserver = nameservers(:shop_ns1) + payload = { + "data": { + "id": nameserver.hostname, + "type": "nameserver", + "domains": ["shop.test", "airport.test", "library.test", "metro.test"], + "attributes": { + "hostname": nameserver.hostname, + "ipv4": "1.1.1.1", + "ipv6": ["2620:119:352::36"] + } + } + } + + put '/repp/v1/registrar/nameservers', headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 2005, json[:code] + assert_equal 'IPv4 should be array [ipv4]', json[:message] + end + + def test_ipv6_isnt_array + nameserver = nameservers(:shop_ns1) + payload = { + "data": { + "id": nameserver.hostname, + "type": "nameserver", + "domains": ["shop.test", "airport.test", "library.test", "metro.test"], + "attributes": { + "hostname": nameserver.hostname, + "ipv4": ["1.1.1.1"], + "ipv6": "2620:119:352::36" + } + } + } + + put '/repp/v1/registrar/nameservers', headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 2005, json[:code] + assert_equal 'IPv6 should be array [ipv6]', json[:message] + end end From cff2b0c41b282898fde216d7a3a1cde0ad27f5ba Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Mon, 15 Feb 2021 13:59:12 +0200 Subject: [PATCH 66/80] added test for bulk changes nameservers if there are array of domains --- .../repp/v1/registrar/nameservers_test.rb | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/integration/repp/v1/registrar/nameservers_test.rb b/test/integration/repp/v1/registrar/nameservers_test.rb index 0e527da98..e58e4651c 100644 --- a/test/integration/repp/v1/registrar/nameservers_test.rb +++ b/test/integration/repp/v1/registrar/nameservers_test.rb @@ -120,4 +120,33 @@ class ReppV1RegistrarNameserversTest < ActionDispatch::IntegrationTest assert_equal 2005, json[:code] assert_equal 'IPv6 should be array [ipv6]', json[:message] end + + def test_bulk_nameservers_change_in_array_of_domains + domain_shop = domains(:shop) + domain_airport = domains(:airport) + + payload = { + "data": { + "type": "nameserver", + "id": "ns1.bestnames.test", + "domains": ["shop.test", "airport.test"], + "attributes": { + "hostname": "ns4.bestnames.test", + "ipv4": ["192.168.1.1"], + "ipv6": ["2620:119:35::36"] + } + } + } + + put '/repp/v1/registrar/nameservers', headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + domain_airport.reload + domain_shop.reload + + refute domain_shop.nameservers.find_by(hostname: 'ns1.bestnames.test').present? + assert domain_shop.nameservers.find_by(hostname: 'ns4.bestnames.test').present? + assert_equal({ hostname: "ns4.bestnames.test", ipv4: ["192.168.1.1"], ipv6: ["2620:119:35::36"] }, json[:data][:attributes]) + assert json[:data][:affected_domains].include? 'airport.test' + assert json[:data][:affected_domains].include? 'shop.test' + end end From d77623c318001876c1abbf4867966d8c8266ffa0 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Mon, 15 Feb 2021 14:24:36 +0200 Subject: [PATCH 67/80] added test for domain tech change prohibited --- .../repp/v1/contacts/tech_replace_test.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/integration/repp/v1/contacts/tech_replace_test.rb b/test/integration/repp/v1/contacts/tech_replace_test.rb index dfc61f6e2..ed8c9d0cc 100644 --- a/test/integration/repp/v1/contacts/tech_replace_test.rb +++ b/test/integration/repp/v1/contacts/tech_replace_test.rb @@ -47,4 +47,22 @@ class ReppV1ContactsTechReplaceTest < ActionDispatch::IntegrationTest assert_equal 2304, json[:code] assert_equal 'New contact must be different from current', json[:message] end + + def test_domain_has_status_tech_change_prohibited + domain_shop = domains(:shop) + domain_shop_tech_contact_id = domain_shop.tech_domain_contacts[0][:contact_id] + old_contact = Contact.find_by(id: domain_shop_tech_contact_id) + new_contact = contacts(:john) + + domain_shop.update(statuses: [DomainStatus::SERVER_TECH_CHANGE_PROHIBITED]) + domain_shop.reload + assert domain_shop.statuses.include? DomainStatus::SERVER_TECH_CHANGE_PROHIBITED + + payload = { current_contact_id: old_contact.code, new_contact_id: new_contact.code } + patch "/repp/v1/domains/contacts", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_equal json[:data][:skipped_domains], ["shop.test"] + assert domain_shop.contacts.find_by(id: domain_shop_tech_contact_id).present? + end end From 50d18388544da8e53260ae8969e5142a1cc76062 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Mon, 15 Feb 2021 15:11:54 +0200 Subject: [PATCH 68/80] added test for renew specif domains if domain renew before expire has small value --- .../repp/v1/domains/renews_test.rb | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/integration/repp/v1/domains/renews_test.rb b/test/integration/repp/v1/domains/renews_test.rb index 3f78907db..fdebc62bd 100644 --- a/test/integration/repp/v1/domains/renews_test.rb +++ b/test/integration/repp/v1/domains/renews_test.rb @@ -41,4 +41,26 @@ class ReppV1DomainsRenewsTest < ActionDispatch::IntegrationTest assert @domain.valid_to, original_valid_to end + + def test_some_test + days_to_renew_domain_before_expire = setting_entries(:days_to_renew_domain_before_expire) + days_to_renew_domain_before_expire.update(value: '1') + days_to_renew_domain_before_expire.reload + + original_valid_to = @domain.valid_to + travel_to @domain.valid_to - 3.days + + one_year = billing_prices(:renew_one_year) + one_year.update(valid_from: @domain.valid_to - 5.days) + one_year.reload + + @auth_headers['Content-Type'] = 'application/json' + payload = { renew: { period: 1, period_unit: 'y' } } + post "/repp/v1/domains/#{@domain.name}/renew", headers: @auth_headers, params: payload.to_json + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 2304, json[:code] + assert_equal 'Object status prohibits operation', json[:message] + end end From dc68f690178d3139e006ba629ddd9c5a8171313d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 15 Feb 2021 15:43:16 +0200 Subject: [PATCH 69/80] Bulk NS change: Verify data type in JSON --- .../repp/v1/registrar/nameservers_controller.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/controllers/repp/v1/registrar/nameservers_controller.rb b/app/controllers/repp/v1/registrar/nameservers_controller.rb index 39f076e9b..87347d1e9 100644 --- a/app/controllers/repp/v1/registrar/nameservers_controller.rb +++ b/app/controllers/repp/v1/registrar/nameservers_controller.rb @@ -4,6 +4,19 @@ module Repp class NameserversController < BaseController before_action :verify_nameserver_existance, only: %i[update] + api :PUT, 'repp/v1/registrar/nameservers' + desc 'bulk nameserver change' + param :data, Hash, required: true, desc: 'Object holding nameserver changes' do + param :type, String, required: true, desc: 'Always set as "nameserver"' + param :id, String, required: true, desc: 'Hostname of replacable nameserver' + param :domains, Array, required: true, desc: 'Array of domain names qualified for ' \ + 'nameserver replacement' + param :attributes, Hash, required: true, desc: 'Object holding new nameserver values' do + param :hostname, String, required: true, desc: 'New hostname of nameserver' + param :ipv4, Array, required: false, desc: 'Array of fixed IPv4 addresses' + param :ipv6, Array, required: false, desc: 'Array of fixed IPv6 addresses' + end + end def update affected, errored = current_user.registrar .replace_nameservers(hostname, From f2e58d5e01be8ba464a96688be50a27c3a8c63d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 15 Feb 2021 15:51:04 +0200 Subject: [PATCH 70/80] Make domains array optional --- app/controllers/repp/v1/registrar/nameservers_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/repp/v1/registrar/nameservers_controller.rb b/app/controllers/repp/v1/registrar/nameservers_controller.rb index 87347d1e9..5ce44caa2 100644 --- a/app/controllers/repp/v1/registrar/nameservers_controller.rb +++ b/app/controllers/repp/v1/registrar/nameservers_controller.rb @@ -9,7 +9,7 @@ module Repp param :data, Hash, required: true, desc: 'Object holding nameserver changes' do param :type, String, required: true, desc: 'Always set as "nameserver"' param :id, String, required: true, desc: 'Hostname of replacable nameserver' - param :domains, Array, required: true, desc: 'Array of domain names qualified for ' \ + param :domains, Array, required: false, desc: 'Array of domain names qualified for ' \ 'nameserver replacement' param :attributes, Hash, required: true, desc: 'Object holding new nameserver values' do param :hostname, String, required: true, desc: 'New hostname of nameserver' From e71ea05fb449c3c157056b0685adefab5561f75f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 15 Feb 2021 15:58:28 +0200 Subject: [PATCH 71/80] REPP: Fix response code for paramInvalid --- app/controllers/repp/v1/base_controller.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/controllers/repp/v1/base_controller.rb b/app/controllers/repp/v1/base_controller.rb index 25cf8fc91..53519195c 100644 --- a/app/controllers/repp/v1/base_controller.rb +++ b/app/controllers/repp/v1/base_controller.rb @@ -16,9 +16,12 @@ module Repp rescue ActiveRecord::RecordNotFound @response = { code: 2303, message: 'Object does not exist' } render(json: @response, status: :not_found) - rescue ActionController::ParameterMissing, Apipie::ParamInvalid, Apipie::ParamMissing => e + rescue ActionController::ParameterMissing, Apipie::ParamMissing => e @response = { code: 2003, message: e } render(json: @response, status: :bad_request) + rescue Apipie::ParamInvalid => e + @response = { code: 2005, message: e } + render(json: @response, status: :bad_request) ensure create_repp_log end From 082d287401c4a360b11d125f3d408bad42610cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 18 Feb 2021 13:00:49 +0200 Subject: [PATCH 72/80] Fix bulk NS change IP validation --- app/controllers/repp/v1/registrar/nameservers_controller.rb | 4 ++-- test/integration/repp/v1/registrar/nameservers_test.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/repp/v1/registrar/nameservers_controller.rb b/app/controllers/repp/v1/registrar/nameservers_controller.rb index 5ce44caa2..0d03bf2a9 100644 --- a/app/controllers/repp/v1/registrar/nameservers_controller.rb +++ b/app/controllers/repp/v1/registrar/nameservers_controller.rb @@ -13,8 +13,8 @@ module Repp 'nameserver replacement' param :attributes, Hash, required: true, desc: 'Object holding new nameserver values' do param :hostname, String, required: true, desc: 'New hostname of nameserver' - param :ipv4, Array, required: false, desc: 'Array of fixed IPv4 addresses' - param :ipv6, Array, required: false, desc: 'Array of fixed IPv6 addresses' + param :ipv4, Array, of: String, required: false, desc: 'Array of fixed IPv4 addresses' + param :ipv6, Array, of: String, required: false, desc: 'Array of fixed IPv6 addresses' end end def update diff --git a/test/integration/repp/v1/registrar/nameservers_test.rb b/test/integration/repp/v1/registrar/nameservers_test.rb index e58e4651c..102649637 100644 --- a/test/integration/repp/v1/registrar/nameservers_test.rb +++ b/test/integration/repp/v1/registrar/nameservers_test.rb @@ -95,7 +95,7 @@ class ReppV1RegistrarNameserversTest < ActionDispatch::IntegrationTest assert_response :bad_request assert_equal 2005, json[:code] - assert_equal 'IPv4 should be array [ipv4]', json[:message] + assert json[:message].include? 'Must be an array of String' end def test_ipv6_isnt_array @@ -118,7 +118,7 @@ class ReppV1RegistrarNameserversTest < ActionDispatch::IntegrationTest assert_response :bad_request assert_equal 2005, json[:code] - assert_equal 'IPv6 should be array [ipv6]', json[:message] + assert json[:message].include? 'Must be an array of String' end def test_bulk_nameservers_change_in_array_of_domains From 83bfc493bbdcf67c9ee89fbfce5d449b9513791a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 22 Mar 2021 15:13:48 +0200 Subject: [PATCH 73/80] Rename admin_domain_contacts_attributes to admin_contacts --- app/controllers/repp/v1/domains_controller.rb | 8 ++++---- app/interactions/actions/domain_create.rb | 7 +++---- lib/deserializers/xml/domain_create.rb | 4 ++-- test/integration/repp/v1/domains/create_test.rb | 4 ++-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 8213f2bb2..05cb5b754 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -35,9 +35,9 @@ module Repp param :ipv4, Array, desc: 'Array of IPv4 addresses' param :ipv6, Array, desc: 'Array of IPv4 addresses' end - param :admin_domain_contacts_attributes, Array, required: false, + param :admin_contacts, Array, required: false, desc: 'Admin domain contacts codes' - param :tech_domain_contacts_attributes, Array, required: false, + param :tech_contacts, Array, required: false, desc: 'Tech domain contacts codes' param :dnskeys_attributes, Array, required: false, desc: 'DNSSEC keys for domain' do param_group :dns_keys_apidoc, Repp::V1::Domains::DnssecController @@ -219,8 +219,8 @@ module Repp params.require(:domain).permit(:name, :registrant_id, :period, :period_unit, :registrar_id, dnskeys_attributes: [%i[flags alg protocol public_key]], nameservers_attributes: [[:hostname, ipv4: [], ipv6: []]], - admin_domain_contacts_attributes: [], - tech_domain_contacts_attributes: []) + admin_contacts: [], + tech_contacts: []) end end end diff --git a/app/interactions/actions/domain_create.rb b/app/interactions/actions/domain_create.rb index 9c2dfba56..4534dfa5e 100644 --- a/app/interactions/actions/domain_create.rb +++ b/app/interactions/actions/domain_create.rb @@ -129,8 +129,8 @@ module Actions def assign_domain_contacts @admin_contacts = [] @tech_contacts = [] - params[:admin_domain_contacts_attributes]&.each { |c| assign_contact(c) } - params[:tech_domain_contacts_attributes]&.each { |c| assign_contact(c, admin: false) } + params[:admin_contacts]&.each { |c| assign_contact(c) } + params[:tech_contacts]&.each { |c| assign_contact(c, admin: false) } domain.admin_domain_contacts_attributes = @admin_contacts domain.tech_domain_contacts_attributes = @tech_contacts @@ -144,8 +144,7 @@ module Actions domain.expire_time = calculate_expiry(period) end - def calculate_expiry(period) - plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym + def calculate_expiry(period) plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day end diff --git a/lib/deserializers/xml/domain_create.rb b/lib/deserializers/xml/domain_create.rb index e251dad88..78642d892 100644 --- a/lib/deserializers/xml/domain_create.rb +++ b/lib/deserializers/xml/domain_create.rb @@ -15,8 +15,8 @@ module Deserializers def call obj = domain - obj[:admin_domain_contacts_attributes] = admin_contacts - obj[:tech_domain_contacts_attributes] = tech_contacts + obj[:admin_contacts] = admin_contacts + obj[:tech_contacts] = tech_contacts obj[:nameservers_attributes] = nameservers obj[:dnskeys_attributes] = dns_keys obj[:legal_document] = legal_document diff --git a/test/integration/repp/v1/domains/create_test.rb b/test/integration/repp/v1/domains/create_test.rb index f3cd4808f..ca1c08c5e 100644 --- a/test/integration/repp/v1/domains/create_test.rb +++ b/test/integration/repp/v1/domains/create_test.rb @@ -94,8 +94,8 @@ class ReppV1DomainsCreateTest < ActionDispatch::IntegrationTest registrant_id: contact.code, period: 1, period_unit: 'y', - admin_domain_contacts_attributes: [ admin_contact.code ], - tech_domain_contacts_attributes: [ tech_contact.code ], + admin_contacts: [ admin_contact.code ], + tech_contacts: [ tech_contact.code ], } } From d6b266459b344cb14f9c448646d705056e28a47c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 22 Mar 2021 15:28:23 +0200 Subject: [PATCH 74/80] REPP: Ditch _id from registrant / registrar attributes --- app/controllers/repp/v1/domains_controller.rb | 6 +++--- app/interactions/actions/domain_create.rb | 8 ++++---- app/interactions/actions/domain_update.rb | 4 ++-- lib/deserializers/xml/domain.rb | 4 ++-- test/integration/repp/v1/domains/create_test.rb | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 05cb5b754..dcf7a15cb 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -27,7 +27,7 @@ module Repp desc 'Create a new domain' param :domain, Hash, required: true, desc: 'Parameters for new domain' do param :name, String, required: true, desc: 'Domain name to be registered' - param :registrant_id, String, required: true, desc: 'Registrant contact code' + param :registrant, String, required: true, desc: 'Registrant contact code' param :period, Integer, required: true, desc: 'Registration period in months or years' param :period_unit, String, required: true, desc: 'Period type (month m) or (year y)' param :nameservers_attributes, Array, required: false, desc: 'Domain nameservers' do @@ -170,7 +170,7 @@ module Repp def forward_registrar_id return unless params[:domain] - params[:domain][:registrar_id] = current_user.registrar.id + params[:domain][:registrar] = current_user.registrar.id end def set_domain @@ -216,7 +216,7 @@ module Repp end def domain_create_params - params.require(:domain).permit(:name, :registrant_id, :period, :period_unit, :registrar_id, + params.require(:domain).permit(:name, :registrant, :period, :period_unit, :registrar, dnskeys_attributes: [%i[flags alg protocol public_key]], nameservers_attributes: [[:hostname, ipv4: [], ipv6: []]], admin_contacts: [], diff --git a/app/interactions/actions/domain_create.rb b/app/interactions/actions/domain_create.rb index 4534dfa5e..ec6e83b0e 100644 --- a/app/interactions/actions/domain_create.rb +++ b/app/interactions/actions/domain_create.rb @@ -66,16 +66,16 @@ module Actions end def assign_registrant - unless params[:registrant_id] + unless params[:registrant] domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) return end - regt = Registrant.find_by(code: params[:registrant_id]) + regt = Registrant.find_by(code: params[:registrant]) if regt domain.registrant = regt else - domain.add_epp_error('2303', 'registrant', params[:registrant_id], %i[registrant not_found]) + domain.add_epp_error('2303', 'registrant', params[:registrant], %i[registrant not_found]) end end @@ -207,7 +207,7 @@ module Actions end def current_registrar - Registrar.find(params[:registrar_id]) + Registrar.find(params[:registrar]) end end end diff --git a/app/interactions/actions/domain_update.rb b/app/interactions/actions/domain_update.rb index e93162fd5..0df036654 100644 --- a/app/interactions/actions/domain_update.rb +++ b/app/interactions/actions/domain_update.rb @@ -49,7 +49,7 @@ module Actions regt = Registrant.find_by(code: params[:registrant][:code]) unless regt - domain.add_epp_error('2303', 'registrant', params[:registrant_id], %i[registrant not_found]) + domain.add_epp_error('2303', 'registrant', params[:registrant], %i[registrant not_found]) return end @@ -234,7 +234,7 @@ module Actions def ask_registrant_verification if verify_registrant_change? && !bypass_verify && Setting.request_confirmation_on_registrant_change_enabled - domain.registrant_verification_asked!(params, params[:registrar_id]) + domain.registrant_verification_asked!(params, params[:registrar]) end end diff --git a/lib/deserializers/xml/domain.rb b/lib/deserializers/xml/domain.rb index c663d4e7e..e406a8de7 100644 --- a/lib/deserializers/xml/domain.rb +++ b/lib/deserializers/xml/domain.rb @@ -11,8 +11,8 @@ module Deserializers def call attributes = { name: if_present('name'), - registrar_id: registrar, - registrant_id: if_present('registrant'), + registrar: registrar, + registrant: if_present('registrant'), reserved_pw: if_present('reserved > pw'), } diff --git a/test/integration/repp/v1/domains/create_test.rb b/test/integration/repp/v1/domains/create_test.rb index ca1c08c5e..bcce43e58 100644 --- a/test/integration/repp/v1/domains/create_test.rb +++ b/test/integration/repp/v1/domains/create_test.rb @@ -17,7 +17,7 @@ class ReppV1DomainsCreateTest < ActionDispatch::IntegrationTest payload = { domain: { name: 'domeener.test', - registrant_id: contact.code, + registrant: contact.code, period: 1, period_unit: 'y' } @@ -39,7 +39,7 @@ class ReppV1DomainsCreateTest < ActionDispatch::IntegrationTest payload = { domain: { name: 'domeener.test', - registrant_id: contact.code, + registrant: contact.code, period: 3, period_unit: 'y' } @@ -61,7 +61,7 @@ class ReppV1DomainsCreateTest < ActionDispatch::IntegrationTest payload = { domain: { name: 'domeener.test', - registrant_id: contact.code, + registrant: contact.code, period: 1, period_unit: 'y', nameservers_attributes: [ @@ -91,7 +91,7 @@ class ReppV1DomainsCreateTest < ActionDispatch::IntegrationTest payload = { domain: { name: 'domeener.test', - registrant_id: contact.code, + registrant: contact.code, period: 1, period_unit: 'y', admin_contacts: [ admin_contact.code ], From 6e624a78980691b87b4c2519a207a75a9ec5cd52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 22 Mar 2021 15:33:37 +0200 Subject: [PATCH 75/80] FIX code styling --- app/controllers/repp/v1/domains_controller.rb | 6 ++---- app/interactions/actions/domain_create.rb | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index dcf7a15cb..99d8c44e5 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -35,10 +35,8 @@ module Repp param :ipv4, Array, desc: 'Array of IPv4 addresses' param :ipv6, Array, desc: 'Array of IPv4 addresses' end - param :admin_contacts, Array, required: false, - desc: 'Admin domain contacts codes' - param :tech_contacts, Array, required: false, - desc: 'Tech domain contacts codes' + param :admin_contacts, Array, required: false, desc: 'Admin domain contacts codes' + param :tech_contacts, Array, required: false, desc: 'Tech domain contacts codes' param :dnskeys_attributes, Array, required: false, desc: 'DNSSEC keys for domain' do param_group :dns_keys_apidoc, Repp::V1::Domains::DnssecController end diff --git a/app/interactions/actions/domain_create.rb b/app/interactions/actions/domain_create.rb index ec6e83b0e..2e735bcce 100644 --- a/app/interactions/actions/domain_create.rb +++ b/app/interactions/actions/domain_create.rb @@ -144,7 +144,8 @@ module Actions domain.expire_time = calculate_expiry(period) end - def calculate_expiry(period) plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym + def calculate_expiry(period) + plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day end From 117b6829908b08b0dbbaa541565ee8040aa1fd82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 22 Mar 2021 16:29:40 +0200 Subject: [PATCH 76/80] Rename auth_info / authorization_code to transfer_code --- app/controllers/repp/v1/domains_controller.rb | 8 ++++--- app/interactions/actions/domain_update.rb | 2 +- lib/deserializers/xml/domain_update.rb | 2 +- lib/serializers/repp/domain.rb | 2 +- .../repp/v1/domains/create_test.rb | 24 +++++++++++++++++++ 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 99d8c44e5..56de83661 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -28,6 +28,8 @@ module Repp param :domain, Hash, required: true, desc: 'Parameters for new domain' do param :name, String, required: true, desc: 'Domain name to be registered' param :registrant, String, required: true, desc: 'Registrant contact code' + param :reserved_pw, String, required: false, desc: 'Reserved password for domain' + param :transfer_code, String, required: false, desc: 'Desired transfer code for domain' param :period, Integer, required: true, desc: 'Registration period in months or years' param :period_unit, String, required: true, desc: 'Period type (month m) or (year y)' param :nameservers_attributes, Array, required: false, desc: 'Domain nameservers' do @@ -71,7 +73,7 @@ module Repp param :verified, [true, false], required: false, desc: 'Registrant change is already verified' end - param :auth_info, String, required: false, desc: 'New authorization code' + param :transfer_code, String, required: false, desc: 'New authorization code' end def update action = Actions::DomainUpdate.new(@domain, params[:domain], false) @@ -215,10 +217,10 @@ module Repp def domain_create_params params.require(:domain).permit(:name, :registrant, :period, :period_unit, :registrar, + :transfer_code, :reserved_pw, dnskeys_attributes: [%i[flags alg protocol public_key]], nameservers_attributes: [[:hostname, ipv4: [], ipv6: []]], - admin_contacts: [], - tech_contacts: []) + admin_contacts: [], tech_contacts: []) end end end diff --git a/app/interactions/actions/domain_update.rb b/app/interactions/actions/domain_update.rb index 0df036654..7da22e539 100644 --- a/app/interactions/actions/domain_update.rb +++ b/app/interactions/actions/domain_update.rb @@ -35,7 +35,7 @@ module Actions end def validate_domain_integrity - domain.auth_info = params[:auth_info] if params[:auth_info] + domain.auth_info = params[:transfer_code] if params[:transfer_code] return unless domain.discarded? diff --git a/lib/deserializers/xml/domain_update.rb b/lib/deserializers/xml/domain_update.rb index 86250a368..eb1b22296 100644 --- a/lib/deserializers/xml/domain_update.rb +++ b/lib/deserializers/xml/domain_update.rb @@ -15,7 +15,7 @@ module Deserializers def call obj = { domain: frame.css('name')&.text, registrant: registrant, contacts: contacts, - auth_info: if_present('authInfo > pw'), nameservers: nameservers, + transfer_code: if_present('authInfo > pw'), nameservers: nameservers, registrar_id: registrar, statuses: statuses, dns_keys: dns_keys, reserved_pw: if_present('reserved > pw'), legal_document: @legal_document } diff --git a/lib/serializers/repp/domain.rb b/lib/serializers/repp/domain.rb index 5821e1568..0f81b6417 100644 --- a/lib/serializers/repp/domain.rb +++ b/lib/serializers/repp/domain.rb @@ -12,7 +12,7 @@ module Serializers name: obj.name, registrant: obj.registrant.code, created_at: obj.created_at, updated_at: obj.updated_at, expire_time: obj.expire_time, outzone_at: obj.outzone_at, delete_date: obj.delete_date, force_delete_date: obj.force_delete_date, - authorization_code: obj.auth_info, contacts: contacts, nameservers: nameservers, + transfer_code: obj.auth_info, contacts: contacts, nameservers: nameservers, dnssec_keys: dnssec_keys, statuses: obj.statuses } diff --git a/test/integration/repp/v1/domains/create_test.rb b/test/integration/repp/v1/domains/create_test.rb index bcce43e58..7907e709e 100644 --- a/test/integration/repp/v1/domains/create_test.rb +++ b/test/integration/repp/v1/domains/create_test.rb @@ -110,4 +110,28 @@ class ReppV1DomainsCreateTest < ActionDispatch::IntegrationTest assert_equal tech_contact, domain.tech_domain_contacts.first.contact assert_equal admin_contact, domain.admin_domain_contacts.first.contact end + + def test_creates_new_domain_with_desired_transfer_code + @auth_headers['Content-Type'] = 'application/json' + contact = contacts(:john) + + payload = { + domain: { + name: 'domeener.test', + registrant: contact.code, + transfer_code: 'ABADIATS', + period: 1, + period_unit: 'y' + } + } + + post "/repp/v1/domains", headers: @auth_headers, params: payload.to_json + json = JSON.parse(response.body, symbolize_names: true) + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + + assert @user.registrar.domains.find_by(name: 'domeener.test').present? + assert_equal 'ABADIATS', @user.registrar.domains.find_by(name: 'domeener.test').transfer_code + end end From 2a3040fb09dd73b057460a9452ac9fca7177f442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 22 Mar 2021 16:44:10 +0200 Subject: [PATCH 77/80] REPP: Get all nameservers for domain --- .../repp/v1/domains/nameservers_controller.rb | 10 +++++++++- config/routes.rb | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/controllers/repp/v1/domains/nameservers_controller.rb b/app/controllers/repp/v1/domains/nameservers_controller.rb index fe38de93c..044e36a20 100644 --- a/app/controllers/repp/v1/domains/nameservers_controller.rb +++ b/app/controllers/repp/v1/domains/nameservers_controller.rb @@ -2,9 +2,17 @@ module Repp module V1 module Domains class NameserversController < BaseController - before_action :set_domain, only: %i[create destroy] + before_action :set_domain, only: %i[index create destroy] before_action :set_nameserver, only: %i[destroy] + api :GET, '/repp/v1/domains/:domain_name/nameservers' + desc "Get domain's nameservers" + def index + nameservers = @domain.nameservers + data = { nameservers: nameservers.as_json(only: %i[hostname ipv4 ipv6]) } + render_success(data: data) + end + api :POST, '/repp/v1/domains/:domain_name/nameservers' desc 'Create new nameserver for domain' param :nameservers, Array, required: true, desc: 'Array of new nameservers' do diff --git a/config/routes.rb b/config/routes.rb index 580747ab1..e17f5c3c6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -61,7 +61,7 @@ Rails.application.routes.draw do end end resources :domains, constraints: { id: /.*/ } do - resources :nameservers, only: %i[create destroy], constraints: { id: /.*/ }, controller: 'domains/nameservers' + resources :nameservers, only: %i[index create destroy], constraints: { id: /.*/ }, controller: 'domains/nameservers' resources :dnssec, only: %i[index create], constraints: { id: /.*/ }, controller: 'domains/dnssec' resources :contacts, only: %i[index create], constraints: { id: /.*/ }, controller: 'domains/contacts' resources :renew, only: %i[create], constraints: { id: /.*/ }, controller: 'domains/renews' From 265e135cd0a7ceb8fc15ebe31eff31b80235bb53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 23 Mar 2021 10:29:15 +0200 Subject: [PATCH 78/80] REPP: Remove fax from contact object --- lib/serializers/repp/contact.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/serializers/repp/contact.rb b/lib/serializers/repp/contact.rb index 834402359..b5d03b5cd 100644 --- a/lib/serializers/repp/contact.rb +++ b/lib/serializers/repp/contact.rb @@ -10,7 +10,7 @@ module Serializers def to_json(obj = contact) json = { id: obj.code, name: obj.name, ident: ident, - email: obj.email, phone: obj.phone, fax: obj.fax, + email: obj.email, phone: obj.phone, auth_info: obj.auth_info, statuses: obj.statuses, disclosed_attributes: obj.disclosed_attributes } From 016c5e802cd30f9544bc3f3655bb7aaefc2e529f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 23 Mar 2021 12:04:03 +0200 Subject: [PATCH 79/80] REPP: Domain info for not-sponsoring registrars --- app/controllers/repp/v1/domains_controller.rb | 7 +++++-- lib/serializers/repp/domain.rb | 13 +++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index 56de83661..e83dfde4c 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -5,7 +5,7 @@ module Repp before_action :set_authorized_domain, only: %i[transfer_info destroy] before_action :validate_registrar_authorization, only: %i[transfer_info destroy] before_action :forward_registrar_id, only: %i[create update destroy] - before_action :set_domain, only: %i[show update] + before_action :set_domain, only: %i[update] api :GET, '/repp/v1/domains' desc 'Get all existing domains' @@ -20,7 +20,10 @@ module Repp api :GET, '/repp/v1/domains/:domain_name' desc 'Get a specific domain' def show - render_success(data: { domain: Serializers::Repp::Domain.new(@domain).to_json }) + @domain = Epp::Domain.find_by!(name: params[:id]) + sponsored = @domain.registrar == current_user.registrar + render_success(data: { domain: Serializers::Repp::Domain.new(@domain, + sponsored: sponsored).to_json }) end api :POST, '/repp/v1/domains' diff --git a/lib/serializers/repp/domain.rb b/lib/serializers/repp/domain.rb index 0f81b6417..519a40456 100644 --- a/lib/serializers/repp/domain.rb +++ b/lib/serializers/repp/domain.rb @@ -3,8 +3,9 @@ module Serializers class Domain attr_reader :domain - def initialize(domain) + def initialize(domain, sponsored: true) @domain = domain + @sponsored = sponsored end def to_json(obj = domain) @@ -12,10 +13,10 @@ module Serializers name: obj.name, registrant: obj.registrant.code, created_at: obj.created_at, updated_at: obj.updated_at, expire_time: obj.expire_time, outzone_at: obj.outzone_at, delete_date: obj.delete_date, force_delete_date: obj.force_delete_date, - transfer_code: obj.auth_info, contacts: contacts, nameservers: nameservers, - dnssec_keys: dnssec_keys, statuses: obj.statuses + contacts: contacts, nameservers: nameservers, dnssec_keys: dnssec_keys, + statuses: obj.statuses, registrar: registrar } - + json[:transfer_code] = obj.auth_info if @sponsored json end @@ -33,6 +34,10 @@ module Serializers public_key: nssec.public_key } end end + + def registrar + { name: domain.registrar.name, website: domain.registrar.website } + end end end end From 546330b178f485e8bbdaef70e6f94617e1eae403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 23 Mar 2021 13:14:31 +0200 Subject: [PATCH 80/80] REPP: Add renew exp_date sanity check --- app/controllers/epp/domains_controller.rb | 7 +------ app/controllers/repp/v1/domains/renews_controller.rb | 3 ++- app/controllers/repp/v1/domains_controller.rb | 4 ++-- app/interactions/actions/domain_renew.rb | 3 +++ lib/deserializers/xml/domain.rb | 1 + lib/serializers/repp/domain.rb | 2 ++ test/integration/repp/v1/domains/renews_test.rb | 8 ++++---- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index 80b7d8843..47a40857a 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -72,11 +72,11 @@ module Epp def renew authorize! :renew, @domain - return handle_errors(@domain) if invalid_expiry_date? registrar_id = current_user.registrar.id renew_params = ::Deserializers::Xml::Domain.new(params[:parsed_frame], registrar_id).call + action = Actions::DomainRenew.new(@domain, renew_params, current_user.registrar) if action.call render_epp_response '/epp/domains/renew' @@ -228,11 +228,6 @@ module Epp statuses == [::DomainStatus::CLIENT_HOLD] end - def invalid_expiry_date? - @domain.validate_exp_dates(params[:parsed_frame].css('curExpDate').text) - @domain.errors[:epp_errors].any? - end - def balance_ok?(operation, period = nil, unit = nil) @domain_pricelist = @domain.pricelist(operation, period.try(:to_i), unit) if @domain_pricelist.try(:price) # checking if price list is not found diff --git a/app/controllers/repp/v1/domains/renews_controller.rb b/app/controllers/repp/v1/domains/renews_controller.rb index eabd9ea16..c356d799a 100644 --- a/app/controllers/repp/v1/domains/renews_controller.rb +++ b/app/controllers/repp/v1/domains/renews_controller.rb @@ -11,6 +11,7 @@ module Repp param :renew, Hash, required: true, desc: 'Renew parameters' do param :period, Integer, required: true, desc: 'Renew period. Month (m) or year (y)' param :period_unit, String, required: true, desc: 'For how many months or years to renew' + param :exp_date, String, required: true, desc: 'Current expiry date for domain' end def create authorize!(:renew, @domain) @@ -36,7 +37,7 @@ module Repp private def renew_params - params.permit(:domain_id, renew: %i[period period_unit]) + params.permit(:domain_id, renew: %i[period period_unit exp_date]) end def validate_renew_period diff --git a/app/controllers/repp/v1/domains_controller.rb b/app/controllers/repp/v1/domains_controller.rb index e83dfde4c..b058f4505 100644 --- a/app/controllers/repp/v1/domains_controller.rb +++ b/app/controllers/repp/v1/domains_controller.rb @@ -21,9 +21,9 @@ module Repp desc 'Get a specific domain' def show @domain = Epp::Domain.find_by!(name: params[:id]) - sponsored = @domain.registrar == current_user.registrar + sponsor = @domain.registrar == current_user.registrar render_success(data: { domain: Serializers::Repp::Domain.new(@domain, - sponsored: sponsored).to_json }) + sponsored: sponsor).to_json }) end api :POST, '/repp/v1/domains' diff --git a/app/interactions/actions/domain_renew.rb b/app/interactions/actions/domain_renew.rb index 58e0662ae..66e29c940 100644 --- a/app/interactions/actions/domain_renew.rb +++ b/app/interactions/actions/domain_renew.rb @@ -16,11 +16,14 @@ module Actions domain.add_renew_epp_errors false else + domain.validate_exp_dates(params[:exp_date]) renew end end def renew + return false if domain.errors[:epp_errors].any? + task = Domains::BulkRenew::SingleDomainRenew.run(domain: domain, period: params[:period], unit: params[:period_unit], diff --git a/lib/deserializers/xml/domain.rb b/lib/deserializers/xml/domain.rb index e406a8de7..f06ec587a 100644 --- a/lib/deserializers/xml/domain.rb +++ b/lib/deserializers/xml/domain.rb @@ -29,6 +29,7 @@ module Deserializers { period: period.text.present? ? Integer(period.text) : 1, period_unit: period.first ? period.first[:unit] : 'y', + exp_date: if_present('curExpDate'), } end diff --git a/lib/serializers/repp/domain.rb b/lib/serializers/repp/domain.rb index 519a40456..60863373c 100644 --- a/lib/serializers/repp/domain.rb +++ b/lib/serializers/repp/domain.rb @@ -8,6 +8,7 @@ module Serializers @sponsored = sponsored end + # rubocop:disable Metrics/AbcSize def to_json(obj = domain) json = { name: obj.name, registrant: obj.registrant.code, created_at: obj.created_at, @@ -19,6 +20,7 @@ module Serializers json[:transfer_code] = obj.auth_info if @sponsored json end + # rubocop:enable Metrics/AbcSize def contacts domain.domain_contacts.map { |c| { code: c.contact_code_cache, type: c.type } } diff --git a/test/integration/repp/v1/domains/renews_test.rb b/test/integration/repp/v1/domains/renews_test.rb index fdebc62bd..c3e73669a 100644 --- a/test/integration/repp/v1/domains/renews_test.rb +++ b/test/integration/repp/v1/domains/renews_test.rb @@ -15,7 +15,7 @@ class ReppV1DomainsRenewsTest < ActionDispatch::IntegrationTest travel_to Time.zone.parse('2010-07-05') @auth_headers['Content-Type'] = 'application/json' - payload = { renew: { period: 1, period_unit: 'y' } } + payload = { renew: { period: 1, period_unit: 'y', exp_date: original_valid_to } } post "/repp/v1/domains/#{@domain.name}/renew", headers: @auth_headers, params: payload.to_json json = JSON.parse(response.body, symbolize_names: true) @@ -31,7 +31,7 @@ class ReppV1DomainsRenewsTest < ActionDispatch::IntegrationTest travel_to Time.zone.parse('2010-07-05') @auth_headers['Content-Type'] = 'application/json' - payload = { renew: { period: 100, period_unit: 'y' } } + payload = { renew: { period: 100, period_unit: 'y', exp_date: original_valid_to } } post "/repp/v1/domains/#{@domain.name}/renew", headers: @auth_headers, params: payload.to_json json = JSON.parse(response.body, symbolize_names: true) @@ -48,14 +48,14 @@ class ReppV1DomainsRenewsTest < ActionDispatch::IntegrationTest days_to_renew_domain_before_expire.reload original_valid_to = @domain.valid_to - travel_to @domain.valid_to - 3.days + travel_to @domain.valid_to - 3.days one_year = billing_prices(:renew_one_year) one_year.update(valid_from: @domain.valid_to - 5.days) one_year.reload @auth_headers['Content-Type'] = 'application/json' - payload = { renew: { period: 1, period_unit: 'y' } } + payload = { renew: { period: 1, period_unit: 'y', exp_date: original_valid_to } } post "/repp/v1/domains/#{@domain.name}/renew", headers: @auth_headers, params: payload.to_json json = JSON.parse(response.body, symbolize_names: true)