From 8a399569fef26ec1f491de8b667c634f8aa348d2 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Wed, 27 Jan 2021 13:42:10 +0200 Subject: [PATCH 01/37] added test for domain tech contacts bulk change if domain has server update prohibited --- test/integration/api/domain_contacts_test.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/integration/api/domain_contacts_test.rb b/test/integration/api/domain_contacts_test.rb index 6704739d1..efd7032b4 100644 --- a/test/integration/api/domain_contacts_test.rb +++ b/test/integration/api/domain_contacts_test.rb @@ -107,6 +107,24 @@ class APIDomainContactsTest < ApplicationIntegrationTest JSON.parse(response.body, symbolize_names: true) end + def test_tech_bulk_changed_when_domain_update_prohibited + domains(:shop).update!(statuses: [DomainStatus::SERVER_UPDATE_PROHIBITED]) + + shop_tech_contact = Contact.find_by(code: 'william-001') + assert domains(:shop).tech_contacts.include?(shop_tech_contact) + + patch '/repp/v1/domains/contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + + assert_response :ok + assert_equal ({ code: 1000, + message: 'Command completed successfully', + data: { affected_domains: ["airport.test"], + skipped_domains: ["shop.test"] }}), + JSON.parse(response.body, symbolize_names: true) + end + private def http_auth_key From 3c1b989723ae3981c418432a81da1f0f9cbbf096 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Fri, 29 Jan 2021 16:13:15 +0500 Subject: [PATCH 02/37] Add check if domain got *UpdateProhibited --- app/models/concerns/domain/bulk_updatable.rb | 17 +++++++++++++++++ app/models/domain.rb | 1 + app/models/tech_domain_contact.rb | 3 +-- 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 app/models/concerns/domain/bulk_updatable.rb diff --git a/app/models/concerns/domain/bulk_updatable.rb b/app/models/concerns/domain/bulk_updatable.rb new file mode 100644 index 000000000..a0aadb95f --- /dev/null +++ b/app/models/concerns/domain/bulk_updatable.rb @@ -0,0 +1,17 @@ +module Concerns + module Domain + module BulkUpdatable + extend ActiveSupport::Concern + + def bulk_update_prohibited? + discarded? || statuses_blocks_update? + end + + def statuses_blocks_update? + prohibited_array = [DomainStatus::SERVER_UPDATE_PROHIBITED, + DomainStatus::CLIENT_UPDATE_PROHIBITED] + prohibited_array.any? { |block_status| statuses.include?(block_status) } + end + end + end +end diff --git a/app/models/domain.rb b/app/models/domain.rb index 3acc08575..53f0fa5b6 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -10,6 +10,7 @@ class Domain < ApplicationRecord include Concerns::Domain::RegistryLockable include Concerns::Domain::Releasable include Concerns::Domain::Disputable + include Concerns::Domain::BulkUpdatable attr_accessor :roles diff --git a/app/models/tech_domain_contact.rb b/app/models/tech_domain_contact.rb index 92799061c..20f21b6ed 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.discarded? + if tech_contact.domain.bulk_update_prohibited? skipped_domains << tech_contact.domain.name next end @@ -18,7 +18,6 @@ class TechDomainContact < DomainContact skipped_domains << tech_contact.domain.name end end - [affected_domains.sort, skipped_domains.sort] end end From d07b6a9c7b08acc70f8cace60646c51585b4cb3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Tue, 2 Feb 2021 13:51:46 +0200 Subject: [PATCH 03/37] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fe9d8a45..45ab590db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +02.02.2021 +* Fixed updateProhibited status not affecting bulk tech contact change operation [#1820](https://github.com/internetee/registry/pull/1820) + 01.02.2021 * Improved tests for admin interface [#1805](https://github.com/internetee/registry/pull/1805) From 1bbacbf56c16b7345ac5d74e2a01410cbf22d56f Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 11 Jan 2021 13:29:22 +0500 Subject: [PATCH 04/37] Fix class/routes namespace for ContactRequest endpoint --- .../api/v1/contact_requests_controller.rb | 23 +++++++++++ app/models/contact_request.rb | 33 ++++++++++++++++ config/routes.rb | 1 + .../api/v1/contact_requests_test.rb | 39 +++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 app/controllers/api/v1/contact_requests_controller.rb create mode 100644 app/models/contact_request.rb create mode 100644 test/integration/api/v1/contact_requests_test.rb diff --git a/app/controllers/api/v1/contact_requests_controller.rb b/app/controllers/api/v1/contact_requests_controller.rb new file mode 100644 index 000000000..0ac379396 --- /dev/null +++ b/app/controllers/api/v1/contact_requests_controller.rb @@ -0,0 +1,23 @@ +module Api + module V1 + class ContactRequestsController < BaseController + before_action :authenticate_shared_key + + # POST api/v1/contact_requests/ + def create + return head(:bad_request) if contact_request_params[:email].blank? + + ContactRequest.save_record(contact_request_params) + head(:created) + rescue ActionController::ParameterMissing + head(:bad_request) + end + + def update; end + + def contact_request_params + params.require(:contact_request).permit(:email, :whois_record_id, :name, :status, :id) + end + end + end +end diff --git a/app/models/contact_request.rb b/app/models/contact_request.rb new file mode 100644 index 000000000..5da1587dc --- /dev/null +++ b/app/models/contact_request.rb @@ -0,0 +1,33 @@ +class ContactRequest < ApplicationRecord + establish_connection :"whois_#{Rails.env}" + self.table_name = 'contact_requests' + + STATUS_NEW = 'new'.freeze + STATUS_CONFIRMED = 'confirmed'.freeze + STATUS_SENT = 'sent'.freeze + STATUSES = [STATUS_NEW, STATUS_CONFIRMED, STATUS_SENT].freeze + + validates :whois_record_id, presence: true + validates :email, presence: true + validates :name, presence: true + validates :status, inclusion: { in: STATUSES } + + attr_readonly :secret, + :valid_to + + def self.save_record(params) + contact_request = new(params) + contact_request.secret = create_random_secret + contact_request.valid_to = set_valid_to_24_hours_from_now + contact_request.status = STATUS_NEW + contact_request.save! + end + + def self.create_random_secret + SecureRandom.hex(64) + end + + def self.set_valid_to_24_hours_from_now + (Time.zone.now + 24.hours) + end +end diff --git a/config/routes.rb b/config/routes.rb index 3042eced4..93897b0f1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -91,6 +91,7 @@ Rails.application.routes.draw do end resources :auctions, only: %i[index show update], param: :uuid + resources :contact_requests, only: %i[create update], param: :uuid resources :bounces, only: %i[create] end diff --git a/test/integration/api/v1/contact_requests_test.rb b/test/integration/api/v1/contact_requests_test.rb new file mode 100644 index 000000000..78525e0b5 --- /dev/null +++ b/test/integration/api/v1/contact_requests_test.rb @@ -0,0 +1,39 @@ +require 'test_helper' + +class ApiV1ContactRequestTest < ActionDispatch::IntegrationTest + def setup + @api_key = "Basic #{ENV['api_shared_key']}" + @headers = { "Authorization": "#{@api_key}" } + @json_body = { "contact_request": valid_contact_request_body }.as_json + end + + def test_authorizes_api_request + post api_v1_contact_requests_path, params: @json_body, headers: @headers + assert_response :created + + invalid_headers = { "Authorization": "Basic invalid_api_key" } + post api_v1_contact_requests_path, params: @json_body, headers: invalid_headers + assert_response :unauthorized + end + + def test_saves_new_contact_request + request_body = @json_body.dup + random_mail = "#{rand(10000..99999)}@registry.test" + request_body['contact_request']['email'] = random_mail + + post api_v1_contact_requests_path, params: request_body, headers: @headers + assert_response :created + + contact_request = ContactRequest.last + assert_equal contact_request.email, random_mail + assert ContactRequest::STATUS_NEW, contact_request.status + end + + def valid_contact_request_body + { + "email": "aaa@bbb.com", + "whois_record_id": "1", + "name": "test" + }.as_json + end +end From b708cebbfdd2f901e1c69886eb6c56c8892d887a Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 11 Jan 2021 14:52:03 +0500 Subject: [PATCH 05/37] Add update endpoint for ContactRequests --- .../api/v1/contact_requests_controller.rb | 16 ++++++-- app/models/contact_request.rb | 5 +++ config/routes.rb | 2 +- test/fixtures/contact_requests.yml | 8 ++++ .../api/v1/contact_requests_test.rb | 39 ++++++++++++++++--- 5 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 test/fixtures/contact_requests.yml diff --git a/app/controllers/api/v1/contact_requests_controller.rb b/app/controllers/api/v1/contact_requests_controller.rb index 0ac379396..114e3c64d 100644 --- a/app/controllers/api/v1/contact_requests_controller.rb +++ b/app/controllers/api/v1/contact_requests_controller.rb @@ -9,14 +9,24 @@ module Api ContactRequest.save_record(contact_request_params) head(:created) - rescue ActionController::ParameterMissing + rescue StandardError head(:bad_request) end - def update; end + def update + return head(:bad_request) if params[:id].blank? + + record = ContactRequest.find_by(id: params[:id]) + return head(:not_found) unless record + + record.update_status(contact_request_params[:status]) + head(:ok) + rescue StandardError + head(:bad_request) + end def contact_request_params - params.require(:contact_request).permit(:email, :whois_record_id, :name, :status, :id) + params.require(:contact_request).permit(:email, :whois_record_id, :name, :status) end end end diff --git a/app/models/contact_request.rb b/app/models/contact_request.rb index 5da1587dc..a49a92f41 100644 --- a/app/models/contact_request.rb +++ b/app/models/contact_request.rb @@ -23,6 +23,11 @@ class ContactRequest < ApplicationRecord contact_request.save! end + def update_status(status) + self.status = status + save! + end + def self.create_random_secret SecureRandom.hex(64) end diff --git a/config/routes.rb b/config/routes.rb index 93897b0f1..1635789fe 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -91,7 +91,7 @@ Rails.application.routes.draw do end resources :auctions, only: %i[index show update], param: :uuid - resources :contact_requests, only: %i[create update], param: :uuid + resources :contact_requests, only: %i[create update], param: :id resources :bounces, only: %i[create] end diff --git a/test/fixtures/contact_requests.yml b/test/fixtures/contact_requests.yml new file mode 100644 index 000000000..030a4d726 --- /dev/null +++ b/test/fixtures/contact_requests.yml @@ -0,0 +1,8 @@ +new: + whois_record_id: 1 + email: aaa@bbb.com + name: Testname + status: new + secret: somesecret + valid_to: 2010-07-05 + diff --git a/test/integration/api/v1/contact_requests_test.rb b/test/integration/api/v1/contact_requests_test.rb index 78525e0b5..f0621b686 100644 --- a/test/integration/api/v1/contact_requests_test.rb +++ b/test/integration/api/v1/contact_requests_test.rb @@ -4,20 +4,22 @@ class ApiV1ContactRequestTest < ActionDispatch::IntegrationTest def setup @api_key = "Basic #{ENV['api_shared_key']}" @headers = { "Authorization": "#{@api_key}" } - @json_body = { "contact_request": valid_contact_request_body }.as_json + @json_create = { "contact_request": valid_contact_request_create }.as_json + @json_update = { "contact_request": valid_contact_request_update }.as_json + @contact_request = contact_requests(:new) end def test_authorizes_api_request - post api_v1_contact_requests_path, params: @json_body, headers: @headers + post api_v1_contact_requests_path, params: @json_create, headers: @headers assert_response :created invalid_headers = { "Authorization": "Basic invalid_api_key" } - post api_v1_contact_requests_path, params: @json_body, headers: invalid_headers + post api_v1_contact_requests_path, params: @json_create, headers: invalid_headers assert_response :unauthorized end def test_saves_new_contact_request - request_body = @json_body.dup + request_body = @json_create.dup random_mail = "#{rand(10000..99999)}@registry.test" request_body['contact_request']['email'] = random_mail @@ -29,11 +31,38 @@ class ApiV1ContactRequestTest < ActionDispatch::IntegrationTest assert ContactRequest::STATUS_NEW, contact_request.status end - def valid_contact_request_body + def test_updates_existing_contact_request + request_body = @json_update.dup + + put api_v1_contact_request_path(@contact_request.id), params: request_body, headers: @headers + assert_response :ok + + @contact_request.reload + assert ContactRequest::STATUS_CONFIRMED, @contact_request.status + end + + def test_not_updates_if_status_error + request_body = @json_update.dup + request_body['contact_request']['status'] = 'some_error_status' + + put api_v1_contact_request_path(@contact_request.id), params: request_body, headers: @headers + assert_response 400 + + @contact_request.reload + assert ContactRequest::STATUS_NEW, @contact_request.status + end + + def valid_contact_request_create { "email": "aaa@bbb.com", "whois_record_id": "1", "name": "test" }.as_json end + + def valid_contact_request_update + { + "status": "#{ContactRequest::STATUS_CONFIRMED}", + }.as_json + end end From 2d510ec3a6758ce4eade3fc6d8beb968a532d8ed Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 11 Jan 2021 14:58:42 +0500 Subject: [PATCH 06/37] Fix CC --- .../api/v1/contact_requests_controller.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v1/contact_requests_controller.rb b/app/controllers/api/v1/contact_requests_controller.rb index 114e3c64d..a02a68606 100644 --- a/app/controllers/api/v1/contact_requests_controller.rb +++ b/app/controllers/api/v1/contact_requests_controller.rb @@ -16,13 +16,18 @@ module Api def update return head(:bad_request) if params[:id].blank? - record = ContactRequest.find_by(id: params[:id]) - return head(:not_found) unless record + result = process_id(params[:id]) + head(result) + end + + def process_id(id) + record = ContactRequest.find_by(id: id) + return :not_found unless record record.update_status(contact_request_params[:status]) - head(:ok) + :ok rescue StandardError - head(:bad_request) + :bad_request end def contact_request_params From 402005cda103017954b7720d86a47e31e2fff157 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 11 Jan 2021 15:30:05 +0500 Subject: [PATCH 07/37] Add IP address saving --- app/controllers/api/v1/contact_requests_controller.rb | 4 ++-- app/models/contact_request.rb | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v1/contact_requests_controller.rb b/app/controllers/api/v1/contact_requests_controller.rb index a02a68606..531b7e506 100644 --- a/app/controllers/api/v1/contact_requests_controller.rb +++ b/app/controllers/api/v1/contact_requests_controller.rb @@ -24,14 +24,14 @@ module Api record = ContactRequest.find_by(id: id) return :not_found unless record - record.update_status(contact_request_params[:status]) + record.update_status(contact_request_params) :ok rescue StandardError :bad_request end def contact_request_params - params.require(:contact_request).permit(:email, :whois_record_id, :name, :status) + params.require(:contact_request).permit(:email, :whois_record_id, :name, :status, :ip) end end end diff --git a/app/models/contact_request.rb b/app/models/contact_request.rb index a49a92f41..7b91bdd78 100644 --- a/app/models/contact_request.rb +++ b/app/models/contact_request.rb @@ -23,8 +23,9 @@ class ContactRequest < ApplicationRecord contact_request.save! end - def update_status(status) - self.status = status + def update_status(params) + self.status = params['status'] + self.ip_address = params['ip'] save! end From 83b5dc6fc783db7696c199a675acdb4aaf3523e6 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 18 Jan 2021 14:23:08 +0500 Subject: [PATCH 08/37] Return created/updated ContactRequest in body --- app/controllers/api/v1/contact_requests_controller.rb | 11 +++++------ app/models/contact_request.rb | 1 + 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/v1/contact_requests_controller.rb b/app/controllers/api/v1/contact_requests_controller.rb index 531b7e506..2b5977f59 100644 --- a/app/controllers/api/v1/contact_requests_controller.rb +++ b/app/controllers/api/v1/contact_requests_controller.rb @@ -7,8 +7,8 @@ module Api def create return head(:bad_request) if contact_request_params[:email].blank? - ContactRequest.save_record(contact_request_params) - head(:created) + contact_request = ContactRequest.save_record(contact_request_params) + render json: contact_request, status: :created rescue StandardError head(:bad_request) end @@ -16,8 +16,7 @@ module Api def update return head(:bad_request) if params[:id].blank? - result = process_id(params[:id]) - head(result) + process_id(params[:id]) end def process_id(id) @@ -25,9 +24,9 @@ module Api return :not_found unless record record.update_status(contact_request_params) - :ok + render json: record, status: :ok rescue StandardError - :bad_request + head :bad_request end def contact_request_params diff --git a/app/models/contact_request.rb b/app/models/contact_request.rb index 7b91bdd78..e6a5e9f7d 100644 --- a/app/models/contact_request.rb +++ b/app/models/contact_request.rb @@ -21,6 +21,7 @@ class ContactRequest < ApplicationRecord contact_request.valid_to = set_valid_to_24_hours_from_now contact_request.status = STATUS_NEW contact_request.save! + contact_request end def update_status(params) From bb7effc3705223f1322f8bbfe644299d0f2fe0ea Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Thu, 4 Feb 2021 12:30:13 +0500 Subject: [PATCH 09/37] Change name of API key --- app/controllers/api/v1/base_controller.rb | 2 +- config/application.yml.sample | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/base_controller.rb b/app/controllers/api/v1/base_controller.rb index b62b3e063..045e4395e 100644 --- a/app/controllers/api/v1/base_controller.rb +++ b/app/controllers/api/v1/base_controller.rb @@ -11,7 +11,7 @@ module Api end def authenticate_shared_key - api_key = "Basic #{ENV['api_shared_key']}" + api_key = "Basic #{ENV['internal_api_key']}" head(:unauthorized) unless api_key == request.authorization end diff --git a/config/application.yml.sample b/config/application.yml.sample index 5885c47a2..21f1df8e0 100644 --- a/config/application.yml.sample +++ b/config/application.yml.sample @@ -90,6 +90,9 @@ registrant_api_auth_allowed_ips: '127.0.0.1, 0.0.0.0' #ips, separated with comma # Bounces API api_shared_key: testkey +# Link to REST-WHOIS API +internal_api_key: testkey + # Base URL (inc. https://) of REST registrant portal # Leave blank to use internal registrant portal registrant_portal_verifications_base_url: '' From 8ed3aaf78151915871869b130e8c3eaf997c96b2 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Thu, 4 Feb 2021 12:52:42 +0200 Subject: [PATCH 10/37] test added --- test/models/white_ip_test.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/models/white_ip_test.rb b/test/models/white_ip_test.rb index 607887730..7a0c6078b 100644 --- a/test/models/white_ip_test.rb +++ b/test/models/white_ip_test.rb @@ -38,6 +38,20 @@ class WhiteIpTest < ActiveSupport::TestCase assert white_ip.valid? end + def test_validates_include_empty_ipv4 + white_ip = WhiteIp.new + + white_ip.ipv4 = '' + white_ip.ipv6 = '001:0db8:85a3:0000:0000:8a2e:0370:7334' + white_ip.registrar = registrars(:bestnames) + + assert_nothing_raised { white_ip.save } + assert white_ip.valid? + + assert WhiteIp.include_ip?(white_ip.ipv6) + assert_not WhiteIp.include_ip?('192.168.1.1') + end + private def valid_white_ip From dc428b3c18804d927eaa2b5de75f36d6c98fd6be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 4 Feb 2021 16:24:01 +0200 Subject: [PATCH 11/37] Fix IPv4/IPv6 parsing for empty string --- app/models/white_ip.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/white_ip.rb b/app/models/white_ip.rb index 417633b12..7bb3ccb37 100644 --- a/app/models/white_ip.rb +++ b/app/models/white_ip.rb @@ -50,10 +50,10 @@ class WhiteIp < ApplicationRecord def ids_including(ip) ipv4 = ipv6 = [] if check_ip4(ip).present? - ipv4 = select { |white_ip| IPAddr.new(white_ip.ipv4, Socket::AF_INET) === check_ip4(ip) } + ipv4 = select { |white_ip| check_ip4(white_ip.ipv4) === check_ip4(ip) } end if check_ip6(ip).present? - ipv6 = select { |white_ip| IPAddr.new(white_ip.ipv6, Socket::AF_INET6) === check_ip6(ip) } + ipv6 = select { |white_ip| check_ip6(white_ip.ipv6) === check_ip6(ip) } end (ipv4 + ipv6).pluck(:id).flatten.uniq end From b34be2c0273b75a1ca3fe29b31a3954ea9a451bc Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Fri, 5 Feb 2021 10:34:32 +0200 Subject: [PATCH 12/37] modifed test --- test/models/white_ip_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/white_ip_test.rb b/test/models/white_ip_test.rb index 7a0c6078b..ba5abe42f 100644 --- a/test/models/white_ip_test.rb +++ b/test/models/white_ip_test.rb @@ -41,7 +41,7 @@ class WhiteIpTest < ActiveSupport::TestCase def test_validates_include_empty_ipv4 white_ip = WhiteIp.new - white_ip.ipv4 = '' + white_ip.ipv4 = nil white_ip.ipv6 = '001:0db8:85a3:0000:0000:8a2e:0370:7334' white_ip.registrar = registrars(:bestnames) From d99dd477c6fd667faf70a30a1faf72a4088d4837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 5 Feb 2021 11:45:58 +0200 Subject: [PATCH 13/37] WhiteIP: Replace empty string with nil --- app/models/white_ip.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/models/white_ip.rb b/app/models/white_ip.rb index 7bb3ccb37..38cee7b6b 100644 --- a/app/models/white_ip.rb +++ b/app/models/white_ip.rb @@ -4,8 +4,13 @@ class WhiteIp < ApplicationRecord validate :valid_ipv4? validate :valid_ipv6? - validate :validate_ipv4_and_ipv6 + before_save :normalize_blank_values + + def normalize_blank_values + %i[ipv4 ipv6].each { |c| self[c].present? || self[c] = nil } + end + def validate_ipv4_and_ipv6 return if ipv4.present? || ipv6.present? errors.add(:base, I18n.t(:ipv4_or_ipv6_must_be_present)) From f4abad7a9fb8e50196d45ff088a152e089159e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Fri, 5 Feb 2021 12:46:14 +0200 Subject: [PATCH 14/37] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45ab590db..064905ba7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +05.02.2021 +* Fixed IPv4 empty string issue in case of IPv6 only entries for IP whitelist [#1833](https://github.com/internetee/registry/issues/1833) + 02.02.2021 * Fixed updateProhibited status not affecting bulk tech contact change operation [#1820](https://github.com/internetee/registry/pull/1820) From a05f21c86cc0160f41f0a4a25e292b9f0a8266c0 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Tue, 26 Jan 2021 13:58:58 +0200 Subject: [PATCH 15/37] added domain admin contacts bulk change tests --- .../api/domain_admin_contacts_test.rb | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 test/integration/api/domain_admin_contacts_test.rb diff --git a/test/integration/api/domain_admin_contacts_test.rb b/test/integration/api/domain_admin_contacts_test.rb new file mode 100644 index 000000000..75b58d318 --- /dev/null +++ b/test/integration/api/domain_admin_contacts_test.rb @@ -0,0 +1,115 @@ +require 'test_helper' + +class APIDomainAdminContactsTest < ApplicationIntegrationTest + def test_replace_all_admin_contacts_of_the_current_registrar + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + + assert_nil domains(:shop).admin_contacts.find_by(code: 'william-001') + assert domains(:shop).admin_contacts.find_by(code: 'john-001') + assert domains(:airport).admin_contacts.find_by(code: 'john-001') + end + + def test_skip_discarded_domains + domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE]) + + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + + assert domains(:airport).admin_contacts.find_by(code: 'william-001') + end + + def test_return_affected_domains_in_alphabetical_order + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + + assert_response :ok + assert_equal ({ code: 1000, message: 'Command completed successfully', data: { affected_domains: %w[airport.test shop.test], + skipped_domains: [] }}), + JSON.parse(response.body, symbolize_names: true) + end + + def test_return_skipped_domains_in_alphabetical_order + domains(:shop).update!(statuses: [DomainStatus::DELETE_CANDIDATE]) + domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE]) + + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + + assert_response :ok + assert_equal %w[airport.test shop.test], JSON.parse(response.body, + symbolize_names: true)[:data][:skipped_domains] + end + + def test_keep_other_admin_contacts_intact + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + + assert domains(:shop).admin_contacts.find_by(code: 'acme-ltd-001') + end + + def test_keep_tech_contacts_intact + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + + assert domains(:airport).tech_contacts.find_by(code: 'william-001') + end + + def test_restrict_contacts_to_the_current_registrar + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'jack-001', + new_contact_id: 'william-002' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + + assert_response :not_found + assert_equal ({ code: 2303, message: 'Object does not exist' }), + JSON.parse(response.body, symbolize_names: true) + end + + def test_non_existent_current_contact + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'non-existent', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + assert_response :not_found + assert_equal ({ code: 2303, message: 'Object does not exist' }), + JSON.parse(response.body, symbolize_names: true) + end + + def test_non_existent_new_contact + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'non-existent' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + assert_response :not_found + assert_equal ({code: 2303, message: 'Object does not exist'}), + JSON.parse(response.body, symbolize_names: true) + end + + def test_disallow_invalid_new_contact + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'invalid' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + assert_response :bad_request + assert_equal ({ code: 2304, message: 'New contact must be valid', data: {} }), + JSON.parse(response.body, symbolize_names: true) + end + + def test_disallow_self_replacement + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'william-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + assert_response :bad_request + assert_equal ({ code: 2304, message: 'New contact must be different from current', data: {} }), + JSON.parse(response.body, symbolize_names: true) + end + + private + + def http_auth_key + ActionController::HttpAuthentication::Basic.encode_credentials('test_bestnames', 'testtest') + end +end From 275da4645a84733ad20ec9db3a7492a27a0f01f4 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Wed, 27 Jan 2021 13:52:42 +0200 Subject: [PATCH 16/37] added test for admin bulk change when domain has status update prohibited --- .../api/domain_admin_contacts_test.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/integration/api/domain_admin_contacts_test.rb b/test/integration/api/domain_admin_contacts_test.rb index 75b58d318..babc58207 100644 --- a/test/integration/api/domain_admin_contacts_test.rb +++ b/test/integration/api/domain_admin_contacts_test.rb @@ -107,6 +107,24 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest JSON.parse(response.body, symbolize_names: true) end + def test_admin_bulk_changed_when_domain_update_prohibited + domains(:shop).update!(statuses: [DomainStatus::SERVER_UPDATE_PROHIBITED]) + + shop_admin_contact = Contact.find_by(code: 'jane-001') + assert domains(:shop).admin_contacts.include?(shop_admin_contact) + + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'jane-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + + assert_response :ok + assert_equal ({ code: 1000, + message: 'Command completed successfully', + data: { affected_domains: ["airport.test"], + skipped_domains: ["shop.test"] }}), + JSON.parse(response.body, symbolize_names: true) + end + private def http_auth_key From efdb445488e9484b827939107de31d2f88b51ac2 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Fri, 29 Jan 2021 14:41:23 +0200 Subject: [PATCH 17/37] added new test, changed contacts values --- .../api/domain_admin_contacts_test.rb | 71 ++++++++++++------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/test/integration/api/domain_admin_contacts_test.rb b/test/integration/api/domain_admin_contacts_test.rb index babc58207..ff56096d2 100644 --- a/test/integration/api/domain_admin_contacts_test.rb +++ b/test/integration/api/domain_admin_contacts_test.rb @@ -1,29 +1,52 @@ require 'test_helper' class APIDomainAdminContactsTest < ApplicationIntegrationTest - def test_replace_all_admin_contacts_of_the_current_registrar - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', - new_contact_id: 'john-001' }, + setup do + @admin_current = domains(:shop).admin_contacts.find_by(code: 'jane-001') + @admin_new = contacts(:william) + + @admin_new.update(ident: @admin_current.ident, + ident_type: @admin_current.ident_type, + ident_country_code: @admin_current.ident_country_code) + end + + def test_replace_all_admin_contacts_when_ident_data_doesnt_match + @admin_new.update(ident: '777' , + ident_type: 'priv', + ident_country_code: 'LV') + + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, + new_contact_id: @admin_new }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } - assert_nil domains(:shop).admin_contacts.find_by(code: 'william-001') - assert domains(:shop).admin_contacts.find_by(code: 'john-001') - assert domains(:airport).admin_contacts.find_by(code: 'john-001') + assert_response :bad_request + assert_equal ({ code: 2304, message: 'New admin contact must have same ident' }), + JSON.parse(response.body, symbolize_names: true) + end + + def test_replace_all_admin_contacts_of_the_current_registrar + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, + new_contact_id: @admin_new }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + + assert_nil domains(:shop).admin_contacts.find_by(code: @admin_current) + assert domains(:shop).admin_contacts.find_by(code: @admin_new) + assert domains(:airport).admin_contacts.find_by(code: @admin_new) end def test_skip_discarded_domains domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE]) - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', - new_contact_id: 'john-001' }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, + new_contact_id: @admin_new }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } - assert domains(:airport).admin_contacts.find_by(code: 'william-001') + assert domains(:shop).admin_contacts.find_by(code: @admin_current) end def test_return_affected_domains_in_alphabetical_order - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', - new_contact_id: 'john-001' }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, + new_contact_id: @admin_new }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :ok @@ -36,8 +59,8 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest domains(:shop).update!(statuses: [DomainStatus::DELETE_CANDIDATE]) domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE]) - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', - new_contact_id: 'john-001' }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, + new_contact_id: @admin_new }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :ok @@ -46,23 +69,23 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest end def test_keep_other_admin_contacts_intact - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', - new_contact_id: 'john-001' }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, + new_contact_id: @admin_new }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } - assert domains(:shop).admin_contacts.find_by(code: 'acme-ltd-001') + assert domains(:airport).admin_contacts.find_by(code: 'john-001') end def test_keep_tech_contacts_intact - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', - new_contact_id: 'john-001' }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, + new_contact_id: @admin_new }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert domains(:airport).tech_contacts.find_by(code: 'william-001') end def test_restrict_contacts_to_the_current_registrar - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'jack-001', + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, new_contact_id: 'william-002' }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } @@ -73,7 +96,7 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest def test_non_existent_current_contact patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'non-existent', - new_contact_id: 'john-001' }, + new_contact_id: @admin_new}, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :not_found assert_equal ({ code: 2303, message: 'Object does not exist' }), @@ -81,7 +104,7 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest end def test_non_existent_new_contact - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, new_contact_id: 'non-existent' }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :not_found @@ -90,7 +113,7 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest end def test_disallow_invalid_new_contact - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, new_contact_id: 'invalid' }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :bad_request @@ -99,8 +122,8 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest end def test_disallow_self_replacement - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'william-001', - new_contact_id: 'william-001' }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, + new_contact_id: @admin_current }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :bad_request assert_equal ({ code: 2304, message: 'New contact must be different from current', data: {} }), From f3f89bedd72ae1a998d6f916cca8232a37bc5c9e Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 1 Feb 2021 15:35:44 +0500 Subject: [PATCH 18/37] Add first version of admin bulk change --- .../v1/domains/admin_contacts_controller.rb | 40 +++++++++++++ app/models/admin_domain_contact.rb | 21 +++++++ app/models/concerns/contact/identical.rb | 6 ++ config/routes.rb | 1 + .../api/domain_admin_contacts_test.rb | 56 +++++++++---------- 5 files changed, 96 insertions(+), 28 deletions(-) create mode 100644 app/controllers/repp/v1/domains/admin_contacts_controller.rb diff --git a/app/controllers/repp/v1/domains/admin_contacts_controller.rb b/app/controllers/repp/v1/domains/admin_contacts_controller.rb new file mode 100644 index 000000000..035cd36fd --- /dev/null +++ b/app/controllers/repp/v1/domains/admin_contacts_controller.rb @@ -0,0 +1,40 @@ +module Repp + module V1 + module Domains + class AdminContactsController < BaseController + before_action :set_current_contact, only: [:update] + before_action :set_new_contact, only: [:update] + + def set_current_contact + @current_contact = current_user.registrar.contacts.find_by!(code: contact_params[:current_contact_id]) + end + + def set_new_contact + @new_contact = current_user.registrar.contacts.find_by!(code: params[:new_contact_id]) + end + + def update + @epp_errors ||= [] + @epp_errors << { code: 2304, msg: 'New contact must be valid' } if @new_contact.invalid? + + unless @new_contact.identical_to?(@current_contact) + @epp_errors << { code: 2304, msg: 'Admin contacts must be identical' } + end + + return handle_errors if @epp_errors.any? + + affected, skipped = AdminDomainContact.replace(@current_contact, @new_contact) + @response = { affected_domains: affected, skipped_domains: skipped } + render_success(data: @response) + end + + private + + def contact_params + params.require(%i[current_contact_id new_contact_id]) + params.permit(:current_contact_id, :new_contact_id) + end + end + end + end +end diff --git a/app/models/admin_domain_contact.rb b/app/models/admin_domain_contact.rb index 14907403d..9fb8166af 100644 --- a/app/models/admin_domain_contact.rb +++ b/app/models/admin_domain_contact.rb @@ -1,2 +1,23 @@ class AdminDomainContact < DomainContact + def self.replace(current_contact, new_contact) + affected_domains = [] + skipped_domains = [] + admin_contacts = where(contact: current_contact) + + admin_contacts.each do |admin_contact| + if admin_contact.domain.discarded? + skipped_domains << admin_contact.domain.name + next + end + begin + admin_contact.contact = new_contact + admin_contact.save! + affected_domains << admin_contact.domain.name + rescue ActiveRecord::RecordNotUnique + skipped_domains << admin_contact.domain.name + end + end + + [affected_domains.sort, skipped_domains.sort] + end end diff --git a/app/models/concerns/contact/identical.rb b/app/models/concerns/contact/identical.rb index f529e09ac..aa527f723 100644 --- a/app/models/concerns/contact/identical.rb +++ b/app/models/concerns/contact/identical.rb @@ -20,6 +20,12 @@ module Concerns::Contact::Identical .where.not(id: id).take end + def identical_to?(contact) + IDENTIFIABLE_ATTRIBUTES.all? do |attribute| + self.attributes[attribute] == contact.attributes[attribute] + end + end + private def identifiable_hash diff --git a/config/routes.rb b/config/routes.rb index 3042eced4..16102f2b6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -64,6 +64,7 @@ Rails.application.routes.draw do get ':id/transfer_info', to: 'domains#transfer_info', constraints: { id: /.*/ } post 'transfer', to: 'domains#transfer' patch 'contacts', to: 'domains/contacts#update' + patch 'admin_contacts', to: 'domains/admin_contacts#update' post 'renew/bulk', to: 'domains/renews#bulk_renew' end end diff --git a/test/integration/api/domain_admin_contacts_test.rb b/test/integration/api/domain_admin_contacts_test.rb index ff56096d2..f1ad9ff27 100644 --- a/test/integration/api/domain_admin_contacts_test.rb +++ b/test/integration/api/domain_admin_contacts_test.rb @@ -5,48 +5,48 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest @admin_current = domains(:shop).admin_contacts.find_by(code: 'jane-001') @admin_new = contacts(:william) - @admin_new.update(ident: @admin_current.ident, - ident_type: @admin_current.ident_type, + @admin_new.update(ident: @admin_current.ident, + ident_type: @admin_current.ident_type, ident_country_code: @admin_current.ident_country_code) end def test_replace_all_admin_contacts_when_ident_data_doesnt_match @admin_new.update(ident: '777' , - ident_type: 'priv', + ident_type: 'priv', ident_country_code: 'LV') - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, - new_contact_id: @admin_new }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, + new_contact_id: @admin_new.code }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :bad_request - assert_equal ({ code: 2304, message: 'New admin contact must have same ident' }), + assert_equal ({ code: 2304, message: 'Admin contacts must be identical', data: {} }), JSON.parse(response.body, symbolize_names: true) end def test_replace_all_admin_contacts_of_the_current_registrar - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, - new_contact_id: @admin_new }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, + new_contact_id: @admin_new.code }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } - assert_nil domains(:shop).admin_contacts.find_by(code: @admin_current) - assert domains(:shop).admin_contacts.find_by(code: @admin_new) - assert domains(:airport).admin_contacts.find_by(code: @admin_new) + assert_nil domains(:shop).admin_contacts.find_by(code: @admin_current.code) + assert domains(:shop).admin_contacts.find_by(code: @admin_new.code) + assert domains(:airport).admin_contacts.find_by(code: @admin_new.code) end def test_skip_discarded_domains domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE]) - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, - new_contact_id: @admin_new }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, + new_contact_id: @admin_new.code }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } - assert domains(:shop).admin_contacts.find_by(code: @admin_current) + assert domains(:shop).admin_contacts.find_by(code: @admin_current.code) end def test_return_affected_domains_in_alphabetical_order - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, - new_contact_id: @admin_new }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, + new_contact_id: @admin_new.code }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :ok @@ -59,8 +59,8 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest domains(:shop).update!(statuses: [DomainStatus::DELETE_CANDIDATE]) domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE]) - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, - new_contact_id: @admin_new }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, + new_contact_id: @admin_new.code }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :ok @@ -69,23 +69,23 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest end def test_keep_other_admin_contacts_intact - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, - new_contact_id: @admin_new }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, + new_contact_id: @admin_new.code }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert domains(:airport).admin_contacts.find_by(code: 'john-001') end def test_keep_tech_contacts_intact - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, - new_contact_id: @admin_new }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, + new_contact_id: @admin_new.code }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert domains(:airport).tech_contacts.find_by(code: 'william-001') end def test_restrict_contacts_to_the_current_registrar - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, new_contact_id: 'william-002' }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } @@ -96,7 +96,7 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest def test_non_existent_current_contact patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'non-existent', - new_contact_id: @admin_new}, + new_contact_id: @admin_new.code}, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :not_found assert_equal ({ code: 2303, message: 'Object does not exist' }), @@ -104,7 +104,7 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest end def test_non_existent_new_contact - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, new_contact_id: 'non-existent' }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :not_found @@ -113,7 +113,7 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest end def test_disallow_invalid_new_contact - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, new_contact_id: 'invalid' }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :bad_request @@ -122,8 +122,8 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest end def test_disallow_self_replacement - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current, - new_contact_id: @admin_current }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, + new_contact_id: @admin_current.code }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :bad_request assert_equal ({ code: 2304, message: 'New contact must be different from current', data: {} }), From 3c0f7b3a86d5366a7c9514afeb4c833ac8895380 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 1 Feb 2021 15:50:31 +0500 Subject: [PATCH 19/37] Modify tests to make sure working pair of contacts is identical --- app/models/admin_domain_contact.rb | 1 - test/integration/api/domain_admin_contacts_test.rb | 8 +++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/models/admin_domain_contact.rb b/app/models/admin_domain_contact.rb index 9fb8166af..426ea2ead 100644 --- a/app/models/admin_domain_contact.rb +++ b/app/models/admin_domain_contact.rb @@ -17,7 +17,6 @@ class AdminDomainContact < DomainContact skipped_domains << admin_contact.domain.name end end - [affected_domains.sort, skipped_domains.sort] end end diff --git a/test/integration/api/domain_admin_contacts_test.rb b/test/integration/api/domain_admin_contacts_test.rb index f1ad9ff27..bea1a9545 100644 --- a/test/integration/api/domain_admin_contacts_test.rb +++ b/test/integration/api/domain_admin_contacts_test.rb @@ -7,7 +7,12 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest @admin_new.update(ident: @admin_current.ident, ident_type: @admin_current.ident_type, - ident_country_code: @admin_current.ident_country_code) + ident_country_code: @admin_current.ident_country_code, + name: @admin_current.name, + email: @admin_current.email, + phone: @admin_current.phone, + fax: @admin_current.fax, + org_name: @admin_current.org_name) end def test_replace_all_admin_contacts_when_ident_data_doesnt_match @@ -25,6 +30,7 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest end def test_replace_all_admin_contacts_of_the_current_registrar + assert @admin_new.identical_to?(@admin_current) patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, new_contact_id: @admin_new.code }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } From 38b7e52ac8b8dd19fac44d6f850855d91ba91323 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 1 Feb 2021 16:08:51 +0500 Subject: [PATCH 20/37] Modify tests to have :airport domain included in processing --- test/integration/api/domain_admin_contacts_test.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/integration/api/domain_admin_contacts_test.rb b/test/integration/api/domain_admin_contacts_test.rb index bea1a9545..cce80e0c3 100644 --- a/test/integration/api/domain_admin_contacts_test.rb +++ b/test/integration/api/domain_admin_contacts_test.rb @@ -3,6 +3,8 @@ require 'test_helper' class APIDomainAdminContactsTest < ApplicationIntegrationTest setup do @admin_current = domains(:shop).admin_contacts.find_by(code: 'jane-001') + domain = domains(:airport) + domain.admin_contacts = [@admin_current] @admin_new = contacts(:william) @admin_new.update(ident: @admin_current.ident, From fc3a764896e473e0cd69a369f843260cf41e978e Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 1 Feb 2021 16:52:38 +0500 Subject: [PATCH 21/37] Fix discarded domains test --- app/models/concerns/contact/identical.rb | 9 ++++++++- test/integration/api/domain_admin_contacts_test.rb | 9 ++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/models/concerns/contact/identical.rb b/app/models/concerns/contact/identical.rb index aa527f723..1a5516bc5 100644 --- a/app/models/concerns/contact/identical.rb +++ b/app/models/concerns/contact/identical.rb @@ -11,6 +11,13 @@ module Concerns::Contact::Identical ident_country_code org_name ] + + IDENTICAL_ATTRIBUTES = %w[ + ident + ident_type + ident_country_code + ] + private_constant :IDENTIFIABLE_ATTRIBUTES def identical(registrar) @@ -21,7 +28,7 @@ module Concerns::Contact::Identical end def identical_to?(contact) - IDENTIFIABLE_ATTRIBUTES.all? do |attribute| + IDENTICAL_ATTRIBUTES.all? do |attribute| self.attributes[attribute] == contact.attributes[attribute] end end diff --git a/test/integration/api/domain_admin_contacts_test.rb b/test/integration/api/domain_admin_contacts_test.rb index cce80e0c3..2e8cbe6da 100644 --- a/test/integration/api/domain_admin_contacts_test.rb +++ b/test/integration/api/domain_admin_contacts_test.rb @@ -9,12 +9,7 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest @admin_new.update(ident: @admin_current.ident, ident_type: @admin_current.ident_type, - ident_country_code: @admin_current.ident_country_code, - name: @admin_current.name, - email: @admin_current.email, - phone: @admin_current.phone, - fax: @admin_current.fax, - org_name: @admin_current.org_name) + ident_country_code: @admin_current.ident_country_code) end def test_replace_all_admin_contacts_when_ident_data_doesnt_match @@ -49,7 +44,7 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest new_contact_id: @admin_new.code }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } - assert domains(:shop).admin_contacts.find_by(code: @admin_current.code) + assert domains(:airport).admin_contacts.find_by(code: @admin_current.code) end def test_return_affected_domains_in_alphabetical_order From da032dad798545dc5e955429ebdbb80b5fd0d8d0 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 1 Feb 2021 17:13:19 +0500 Subject: [PATCH 22/37] Add BulkUpdatable concern, fix tests --- app/models/admin_domain_contact.rb | 2 +- .../api/domain_admin_contacts_test.rb | 18 ++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/app/models/admin_domain_contact.rb b/app/models/admin_domain_contact.rb index 426ea2ead..d84ac7793 100644 --- a/app/models/admin_domain_contact.rb +++ b/app/models/admin_domain_contact.rb @@ -5,7 +5,7 @@ class AdminDomainContact < DomainContact admin_contacts = where(contact: current_contact) admin_contacts.each do |admin_contact| - if admin_contact.domain.discarded? + if admin_contact.domain.bulk_update_prohibited? skipped_domains << admin_contact.domain.name next end diff --git a/test/integration/api/domain_admin_contacts_test.rb b/test/integration/api/domain_admin_contacts_test.rb index 2e8cbe6da..cd5b92865 100644 --- a/test/integration/api/domain_admin_contacts_test.rb +++ b/test/integration/api/domain_admin_contacts_test.rb @@ -4,7 +4,7 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest setup do @admin_current = domains(:shop).admin_contacts.find_by(code: 'jane-001') domain = domains(:airport) - domain.admin_contacts = [@admin_current] + domain.admin_contacts << @admin_current @admin_new = contacts(:william) @admin_new.update(ident: @admin_current.ident, @@ -48,6 +48,8 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest end def test_return_affected_domains_in_alphabetical_order + domain = domains(:airport) + domain.admin_contacts = [@admin_current] patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, new_contact_id: @admin_new.code }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } @@ -124,23 +126,15 @@ class APIDomainAdminContactsTest < ApplicationIntegrationTest JSON.parse(response.body, symbolize_names: true) end - def test_disallow_self_replacement - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, - new_contact_id: @admin_current.code }, - headers: { 'HTTP_AUTHORIZATION' => http_auth_key } - assert_response :bad_request - assert_equal ({ code: 2304, message: 'New contact must be different from current', data: {} }), - JSON.parse(response.body, symbolize_names: true) - end - def test_admin_bulk_changed_when_domain_update_prohibited domains(:shop).update!(statuses: [DomainStatus::SERVER_UPDATE_PROHIBITED]) + domains(:airport).admin_contacts = [@admin_current] shop_admin_contact = Contact.find_by(code: 'jane-001') assert domains(:shop).admin_contacts.include?(shop_admin_contact) - patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'jane-001', - new_contact_id: 'john-001' }, + patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code, + new_contact_id: @admin_new.code }, headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :ok From f6a2d91d61c311ceff292dd210b5ed54743b6eed Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 1 Feb 2021 17:21:29 +0500 Subject: [PATCH 23/37] Fix CC issues --- .../v1/domains/admin_contacts_controller.rb | 23 ++------------ .../v1/domains/base_contacts_controller.rb | 31 +++++++++++++++++++ .../repp/v1/domains/contacts_controller.rb | 25 ++------------- app/models/admin_domain_contact.rb | 4 +++ app/models/concerns/contact/identical.rb | 4 +-- 5 files changed, 41 insertions(+), 46 deletions(-) create mode 100644 app/controllers/repp/v1/domains/base_contacts_controller.rb diff --git a/app/controllers/repp/v1/domains/admin_contacts_controller.rb b/app/controllers/repp/v1/domains/admin_contacts_controller.rb index 035cd36fd..2e9a285eb 100644 --- a/app/controllers/repp/v1/domains/admin_contacts_controller.rb +++ b/app/controllers/repp/v1/domains/admin_contacts_controller.rb @@ -1,21 +1,9 @@ module Repp module V1 module Domains - class AdminContactsController < BaseController - before_action :set_current_contact, only: [:update] - before_action :set_new_contact, only: [:update] - - def set_current_contact - @current_contact = current_user.registrar.contacts.find_by!(code: contact_params[:current_contact_id]) - end - - def set_new_contact - @new_contact = current_user.registrar.contacts.find_by!(code: params[:new_contact_id]) - end - + class AdminContactsController < BaseContactsController def update - @epp_errors ||= [] - @epp_errors << { code: 2304, msg: 'New contact must be valid' } if @new_contact.invalid? + super unless @new_contact.identical_to?(@current_contact) @epp_errors << { code: 2304, msg: 'Admin contacts must be identical' } @@ -27,13 +15,6 @@ module Repp @response = { affected_domains: affected, skipped_domains: skipped } render_success(data: @response) end - - private - - def contact_params - params.require(%i[current_contact_id new_contact_id]) - params.permit(:current_contact_id, :new_contact_id) - end end end end diff --git a/app/controllers/repp/v1/domains/base_contacts_controller.rb b/app/controllers/repp/v1/domains/base_contacts_controller.rb new file mode 100644 index 000000000..b601c5313 --- /dev/null +++ b/app/controllers/repp/v1/domains/base_contacts_controller.rb @@ -0,0 +1,31 @@ +module Repp + module V1 + module Domains + class BaseContactsController < BaseController + before_action :set_current_contact, only: [:update] + before_action :set_new_contact, only: [:update] + + def set_current_contact + @current_contact = current_user.registrar.contacts + .find_by!(code: contact_params[:current_contact_id]) + end + + def set_new_contact + @new_contact = current_user.registrar.contacts.find_by!(code: params[:new_contact_id]) + end + + def update + @epp_errors ||= [] + @epp_errors << { code: 2304, msg: 'New contact must be valid' } if @new_contact.invalid? + end + + private + + def contact_params + params.require(%i[current_contact_id new_contact_id]) + params.permit(:current_contact_id, :new_contact_id) + end + end + end + end +end diff --git a/app/controllers/repp/v1/domains/contacts_controller.rb b/app/controllers/repp/v1/domains/contacts_controller.rb index 75404e0c6..131615570 100644 --- a/app/controllers/repp/v1/domains/contacts_controller.rb +++ b/app/controllers/repp/v1/domains/contacts_controller.rb @@ -1,23 +1,9 @@ module Repp module V1 module Domains - class ContactsController < BaseController - before_action :set_current_contact, only: [:update] - before_action :set_new_contact, only: [:update] - - def set_current_contact - @current_contact = current_user.registrar.contacts.find_by!( - code: contact_params[:current_contact_id] - ) - end - - def set_new_contact - @new_contact = current_user.registrar.contacts.find_by!(code: params[:new_contact_id]) - end - + class ContactsController < BaseContactsController def update - @epp_errors ||= [] - @epp_errors << { code: 2304, msg: 'New contact must be valid' } if @new_contact.invalid? + super if @new_contact == @current_contact @epp_errors << { code: 2304, msg: 'New contact must be different from current' } @@ -29,13 +15,6 @@ module Repp @response = { affected_domains: affected, skipped_domains: skipped } render_success(data: @response) end - - private - - def contact_params - params.require(%i[current_contact_id new_contact_id]) - params.permit(:current_contact_id, :new_contact_id) - end end end end diff --git a/app/models/admin_domain_contact.rb b/app/models/admin_domain_contact.rb index d84ac7793..7ccf3efcb 100644 --- a/app/models/admin_domain_contact.rb +++ b/app/models/admin_domain_contact.rb @@ -1,4 +1,6 @@ class AdminDomainContact < DomainContact + # rubocop:disable Metrics/AbcSize + # rubocop:disable Metrics/MethodLength def self.replace(current_contact, new_contact) affected_domains = [] skipped_domains = [] @@ -19,4 +21,6 @@ class AdminDomainContact < DomainContact end [affected_domains.sort, skipped_domains.sort] end + # rubocop:enable Metrics/AbcSize + # rubocop:enable Metrics/MethodLength end diff --git a/app/models/concerns/contact/identical.rb b/app/models/concerns/contact/identical.rb index 1a5516bc5..5327d1704 100644 --- a/app/models/concerns/contact/identical.rb +++ b/app/models/concerns/contact/identical.rb @@ -16,7 +16,7 @@ module Concerns::Contact::Identical ident ident_type ident_country_code - ] + ].freeze private_constant :IDENTIFIABLE_ATTRIBUTES @@ -29,7 +29,7 @@ module Concerns::Contact::Identical def identical_to?(contact) IDENTICAL_ATTRIBUTES.all? do |attribute| - self.attributes[attribute] == contact.attributes[attribute] + attributes[attribute] == contact.attributes[attribute] end end From fbad7b00b27c785365bca23150672303cb66682d Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Fri, 5 Feb 2021 15:12:36 +0500 Subject: [PATCH 24/37] Refactor bulk_change & tech_contact controllers code to be more reusable --- .../registrar/bulk_change_controller.rb | 30 ++++++++++++++++++ .../registrar/tech_contacts_controller.rb | 31 +++---------------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/app/controllers/registrar/bulk_change_controller.rb b/app/controllers/registrar/bulk_change_controller.rb index 801ab0516..218e7dc5d 100644 --- a/app/controllers/registrar/bulk_change_controller.rb +++ b/app/controllers/registrar/bulk_change_controller.rb @@ -26,6 +26,36 @@ class Registrar private + def do_request(request, uri) + if Rails.env.test? + response = Net::HTTP.start(uri.hostname, uri.port, + use_ssl: (uri.scheme == 'https'), + verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http| + http.request(request) + end + elsif Rails.env.development? + client_cert = File.read(ENV['cert_path']) + client_key = File.read(ENV['key_path']) + response = Net::HTTP.start(uri.hostname, uri.port, + use_ssl: (uri.scheme == 'https'), + verify_mode: OpenSSL::SSL::VERIFY_NONE, + cert: OpenSSL::X509::Certificate.new(client_cert), + key: OpenSSL::PKey::RSA.new(client_key)) do |http| + http.request(request) + end + else + client_cert = File.read(ENV['cert_path']) + client_key = File.read(ENV['key_path']) + response = Net::HTTP.start(uri.hostname, uri.port, + use_ssl: (uri.scheme == 'https'), + cert: OpenSSL::X509::Certificate.new(client_cert), + key: OpenSSL::PKey::RSA.new(client_key)) do |http| + http.request(request) + end + end + response + end + def ready_to_renew? domain_ids_for_bulk_renew.present? && params[:renew].present? end diff --git a/app/controllers/registrar/tech_contacts_controller.rb b/app/controllers/registrar/tech_contacts_controller.rb index 001651250..5cb0e8ee6 100644 --- a/app/controllers/registrar/tech_contacts_controller.rb +++ b/app/controllers/registrar/tech_contacts_controller.rb @@ -1,9 +1,11 @@ class Registrar class TechContactsController < BulkChangeController + BASE_URL = URI.parse("#{ENV['repp_url']}domains/contacts").freeze + def update authorize! :manage, :repp - uri = URI.parse("#{ENV['repp_url']}domains/contacts") + uri = BASE_URL request = Net::HTTP::Patch.new(uri) request.set_form_data(current_contact_id: params[:current_contact_id], @@ -11,32 +13,7 @@ class Registrar request.basic_auth(current_registrar_user.username, current_registrar_user.plain_text_password) - if Rails.env.test? - response = Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http| - http.request(request) - end - elsif Rails.env.development? - client_cert = File.read(ENV['cert_path']) - client_key = File.read(ENV['key_path']) - response = Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - verify_mode: OpenSSL::SSL::VERIFY_NONE, - cert: OpenSSL::X509::Certificate.new(client_cert), - key: OpenSSL::PKey::RSA.new(client_key)) do |http| - http.request(request) - end - else - client_cert = File.read(ENV['cert_path']) - client_key = File.read(ENV['key_path']) - response = Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - cert: OpenSSL::X509::Certificate.new(client_cert), - key: OpenSSL::PKey::RSA.new(client_key)) do |http| - http.request(request) - end - end + response = do_request(request, uri) parsed_response = JSON.parse(response.body, symbolize_names: true) From 3979fc5f8f1702dd271200d58393e9d2c33547c0 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Fri, 5 Feb 2021 15:27:10 +0500 Subject: [PATCH 25/37] Fix CC issues --- .../registrar/bulk_change_controller.rb | 82 +++++++++++++------ .../registrar/domain_transfers_controller.rb | 27 +----- .../registrar/nameservers_controller.rb | 27 +----- .../registrar/tech_contacts_controller.rb | 24 ++---- 4 files changed, 65 insertions(+), 95 deletions(-) diff --git a/app/controllers/registrar/bulk_change_controller.rb b/app/controllers/registrar/bulk_change_controller.rb index 218e7dc5d..63d7b6cb1 100644 --- a/app/controllers/registrar/bulk_change_controller.rb +++ b/app/controllers/registrar/bulk_change_controller.rb @@ -26,36 +26,70 @@ class Registrar private - def do_request(request, uri) - if Rails.env.test? - response = Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http| - http.request(request) - end - elsif Rails.env.development? - client_cert = File.read(ENV['cert_path']) - client_key = File.read(ENV['key_path']) - response = Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - verify_mode: OpenSSL::SSL::VERIFY_NONE, - cert: OpenSSL::X509::Certificate.new(client_cert), - key: OpenSSL::PKey::RSA.new(client_key)) do |http| - http.request(request) + def process_response(response:, start_notice: "", active_tab:) + parsed_response = JSON.parse(response.body, symbolize_names: true) + + if response.code == '200' + notices = [start_notice] + + notices << "#{t('registrar.tech_contacts.process_request.affected_domains')}: " \ + "#{parsed_response[:data][:affected_domains].join(', ')}" + + if parsed_response[:data][:skipped_domains] + notices << "#{t('registrar.tech_contacts.process_request.skipped_domains')}: " \ + "#{parsed_response[:data][:skipped_domains].join(', ')}" end + + flash[:notice] = notices.join(', ') + redirect_to registrar_domains_url else - client_cert = File.read(ENV['cert_path']) - client_key = File.read(ENV['key_path']) - response = Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - cert: OpenSSL::X509::Certificate.new(client_cert), - key: OpenSSL::PKey::RSA.new(client_key)) do |http| - http.request(request) - end + @error = response.code == '404' ? 'Contact(s) not found' : parsed_response[:message] + render file: 'registrar/bulk_change/new', locals: { active_tab: active_tab } end + end + + def do_request(request, uri) + response = if Rails.env.test? + do_test_request(request, uri) + elsif Rails.env.development? + do_dev_request(request, uri) + else + do_live_request(request, uri) + end response end + def do_live_request(request, uri) + client_cert = File.read(ENV['cert_path']) + client_key = File.read(ENV['key_path']) + Net::HTTP.start(uri.hostname, uri.port, + use_ssl: (uri.scheme == 'https'), + cert: OpenSSL::X509::Certificate.new(client_cert), + key: OpenSSL::PKey::RSA.new(client_key)) do |http| + http.request(request) + end + end + + def do_dev_request(request, uri) + client_cert = File.read(ENV['cert_path']) + client_key = File.read(ENV['key_path']) + Net::HTTP.start(uri.hostname, uri.port, + use_ssl: (uri.scheme == 'https'), + verify_mode: OpenSSL::SSL::VERIFY_NONE, + cert: OpenSSL::X509::Certificate.new(client_cert), + key: OpenSSL::PKey::RSA.new(client_key)) do |http| + http.request(request) + end + end + + def do_test_request(request, uri) + Net::HTTP.start(uri.hostname, uri.port, + use_ssl: (uri.scheme == 'https'), + verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http| + http.request(request) + end + end + def ready_to_renew? domain_ids_for_bulk_renew.present? && params[:renew].present? end diff --git a/app/controllers/registrar/domain_transfers_controller.rb b/app/controllers/registrar/domain_transfers_controller.rb index 584a50d33..e055c38d8 100644 --- a/app/controllers/registrar/domain_transfers_controller.rb +++ b/app/controllers/registrar/domain_transfers_controller.rb @@ -25,32 +25,7 @@ class Registrar current_registrar_user.plain_text_password) - if Rails.env.test? - response = Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http| - http.request(request) - end - elsif Rails.env.development? - client_cert = File.read(ENV['cert_path']) - client_key = File.read(ENV['key_path']) - response = Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - verify_mode: OpenSSL::SSL::VERIFY_NONE, - cert: OpenSSL::X509::Certificate.new(client_cert), - key: OpenSSL::PKey::RSA.new(client_key)) do |http| - http.request(request) - end - else - client_cert = File.read(ENV['cert_path']) - client_key = File.read(ENV['key_path']) - response = Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - cert: OpenSSL::X509::Certificate.new(client_cert), - key: OpenSSL::PKey::RSA.new(client_key)) do |http| - http.request(request) - end - end + response = do_request(request, uri) parsed_response = JSON.parse(response.body, symbolize_names: true) diff --git a/app/controllers/registrar/nameservers_controller.rb b/app/controllers/registrar/nameservers_controller.rb index 52c43bb1d..3eb23cd48 100644 --- a/app/controllers/registrar/nameservers_controller.rb +++ b/app/controllers/registrar/nameservers_controller.rb @@ -18,32 +18,7 @@ class Registrar request.basic_auth(current_registrar_user.username, current_registrar_user.plain_text_password) - if Rails.env.test? - response = Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http| - http.request(request) - end - elsif Rails.env.development? - client_cert = File.read(ENV['cert_path']) - client_key = File.read(ENV['key_path']) - response = Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - verify_mode: OpenSSL::SSL::VERIFY_NONE, - cert: OpenSSL::X509::Certificate.new(client_cert), - key: OpenSSL::PKey::RSA.new(client_key)) do |http| - http.request(request) - end - else - client_cert = File.read(ENV['cert_path']) - client_key = File.read(ENV['key_path']) - response = Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - cert: OpenSSL::X509::Certificate.new(client_cert), - key: OpenSSL::PKey::RSA.new(client_key)) do |http| - http.request(request) - end - end + response = do_request(request, uri) parsed_response = JSON.parse(response.body, symbolize_names: true) diff --git a/app/controllers/registrar/tech_contacts_controller.rb b/app/controllers/registrar/tech_contacts_controller.rb index 5cb0e8ee6..90dc333f6 100644 --- a/app/controllers/registrar/tech_contacts_controller.rb +++ b/app/controllers/registrar/tech_contacts_controller.rb @@ -1,12 +1,12 @@ class Registrar class TechContactsController < BulkChangeController BASE_URL = URI.parse("#{ENV['repp_url']}domains/contacts").freeze + ACTIVE_TAB = :technical_contact def update authorize! :manage, :repp uri = BASE_URL - request = Net::HTTP::Patch.new(uri) request.set_form_data(current_contact_id: params[:current_contact_id], new_contact_id: params[:new_contact_id]) @@ -15,25 +15,11 @@ class Registrar response = do_request(request, uri) - parsed_response = JSON.parse(response.body, symbolize_names: true) + start_notice = t('registrar.tech_contacts.process_request.replaced') - if response.code == '200' - notices = [t('.replaced')] - - notices << "#{t('.affected_domains')}: " \ - "#{parsed_response[:data][:affected_domains].join(', ')}" - - if parsed_response[:data][:skipped_domains] - notices << "#{t('.skipped_domains')}: " \ - "#{parsed_response[:data][:skipped_domains].join(', ')}" - end - - flash[:notice] = notices.join(', ') - redirect_to registrar_domains_url - else - @error = response.code == '404' ? 'Contact(s) not found' : parsed_response[:message] - render file: 'registrar/bulk_change/new', locals: { active_tab: :technical_contact } - end + process_response(response: response, + start_notice: start_notice, + active_tab: ACTIVE_TAB) end end end From 489cd2f7e50da44f7a42f923f71466680be69522 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Fri, 5 Feb 2021 15:59:34 +0500 Subject: [PATCH 26/37] Fix i18n --- .../registrar/bulk_change_controller.rb | 25 +++++++++++-------- .../registrar/tech_contacts_controller.rb | 2 +- config/locales/registrar/bulk_change.en.yml | 3 +++ config/locales/registrar/tech_contacts.en.yml | 4 +++ 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/app/controllers/registrar/bulk_change_controller.rb b/app/controllers/registrar/bulk_change_controller.rb index 63d7b6cb1..b11883d6a 100644 --- a/app/controllers/registrar/bulk_change_controller.rb +++ b/app/controllers/registrar/bulk_change_controller.rb @@ -26,19 +26,11 @@ class Registrar private - def process_response(response:, start_notice: "", active_tab:) + def process_response(response:, start_notice: '', active_tab:) parsed_response = JSON.parse(response.body, symbolize_names: true) if response.code == '200' - notices = [start_notice] - - notices << "#{t('registrar.tech_contacts.process_request.affected_domains')}: " \ - "#{parsed_response[:data][:affected_domains].join(', ')}" - - if parsed_response[:data][:skipped_domains] - notices << "#{t('registrar.tech_contacts.process_request.skipped_domains')}: " \ - "#{parsed_response[:data][:skipped_domains].join(', ')}" - end + notices = success_notices(parsed_response, start_notice) flash[:notice] = notices.join(', ') redirect_to registrar_domains_url @@ -48,6 +40,19 @@ class Registrar end end + def success_notices(parsed_response, start_notice) + notices = [start_notice] + + notices << "#{t('.affected_domains')}: " \ + "#{parsed_response[:data][:affected_domains].join(', ')}" + + if parsed_response[:data][:skipped_domains] + notices << "#{t('.skipped_domains')}: " \ + "#{parsed_response[:data][:skipped_domains].join(', ')}" + end + notices + end + def do_request(request, uri) response = if Rails.env.test? do_test_request(request, uri) diff --git a/app/controllers/registrar/tech_contacts_controller.rb b/app/controllers/registrar/tech_contacts_controller.rb index 90dc333f6..3cddb5f36 100644 --- a/app/controllers/registrar/tech_contacts_controller.rb +++ b/app/controllers/registrar/tech_contacts_controller.rb @@ -15,7 +15,7 @@ class Registrar response = do_request(request, uri) - start_notice = t('registrar.tech_contacts.process_request.replaced') + start_notice = t('.replaced') process_response(response: response, start_notice: start_notice, diff --git a/config/locales/registrar/bulk_change.en.yml b/config/locales/registrar/bulk_change.en.yml index 75becfada..58d5fce97 100644 --- a/config/locales/registrar/bulk_change.en.yml +++ b/config/locales/registrar/bulk_change.en.yml @@ -4,6 +4,7 @@ en: new: header: Bulk change technical_contact: Technical contact + admin_contact: Admin contact nameserver: Nameserver bulk_transfer: Bulk transfer bulk_renew: Bulk renew @@ -38,3 +39,5 @@ en: domain_ids: Domains for bulk renewal current_balance: Current balance period: Period + affected_domains: Affected domains + skipped_domains: Skipped domains diff --git a/config/locales/registrar/tech_contacts.en.yml b/config/locales/registrar/tech_contacts.en.yml index bf57f0cc7..b6e5d041b 100644 --- a/config/locales/registrar/tech_contacts.en.yml +++ b/config/locales/registrar/tech_contacts.en.yml @@ -5,3 +5,7 @@ en: replaced: Technical contacts have been successfully replaced. affected_domains: Affected domains skipped_domains: Skipped domains + process_request: + affected_domains: Affected domains + skipped_domains: Skipped domains + replaced: Technical contacts have been successfully replaced. From fca12fdb34f57550daa6b7623383a5720a16e25a Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Fri, 5 Feb 2021 16:51:38 +0500 Subject: [PATCH 27/37] Add a view and routes --- .codeclimate.yml | 6 +- .../registrar/admin_contacts_controller.rb | 19 ++++++ .../registrar/bulk_change_controller.rb | 9 +++ .../registrar/tech_contacts_controller.rb | 8 +-- .../bulk_change/_admin_contact_form.html.erb | 60 +++++++++++++++++++ app/views/registrar/bulk_change/new.html.erb | 9 +++ .../locales/registrar/admin_contacts.en.yml | 6 ++ config/locales/registrar/bulk_change.en.yml | 10 ++++ config/routes.rb | 1 + 9 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 app/controllers/registrar/admin_contacts_controller.rb create mode 100644 app/views/registrar/bulk_change/_admin_contact_form.html.erb create mode 100644 config/locales/registrar/admin_contacts.en.yml diff --git a/.codeclimate.yml b/.codeclimate.yml index 2324522fc..31da9b9cb 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -16,8 +16,10 @@ plugins: enabled: true config: languages: - - ruby - - javascript + ruby: + mass_threshold: 100 + javascript: + mass_threshold: 100 eslint: enabled: true channel: eslint-5 diff --git a/app/controllers/registrar/admin_contacts_controller.rb b/app/controllers/registrar/admin_contacts_controller.rb new file mode 100644 index 000000000..55cfbae9e --- /dev/null +++ b/app/controllers/registrar/admin_contacts_controller.rb @@ -0,0 +1,19 @@ +class Registrar + class AdminContactsController < BulkChangeController + BASE_URL = URI.parse("#{ENV['repp_url']}domains/admin_contacts").freeze + ACTIVE_TAB = :admin_contact + + def update + authorize! :manage, :repp + + uri = BASE_URL + request = form_request(uri) + response = do_request(request, uri) + start_notice = t('.replaced') + + process_response(response: response, + start_notice: start_notice, + active_tab: ACTIVE_TAB) + end + end +end diff --git a/app/controllers/registrar/bulk_change_controller.rb b/app/controllers/registrar/bulk_change_controller.rb index b11883d6a..74bbf89e8 100644 --- a/app/controllers/registrar/bulk_change_controller.rb +++ b/app/controllers/registrar/bulk_change_controller.rb @@ -26,6 +26,15 @@ class Registrar private + def form_request(uri) + request = Net::HTTP::Patch.new(uri) + request.set_form_data(current_contact_id: params[:current_contact_id], + new_contact_id: params[:new_contact_id]) + request.basic_auth(current_registrar_user.username, + current_registrar_user.plain_text_password) + request + end + def process_response(response:, start_notice: '', active_tab:) parsed_response = JSON.parse(response.body, symbolize_names: true) diff --git a/app/controllers/registrar/tech_contacts_controller.rb b/app/controllers/registrar/tech_contacts_controller.rb index 3cddb5f36..cc9238730 100644 --- a/app/controllers/registrar/tech_contacts_controller.rb +++ b/app/controllers/registrar/tech_contacts_controller.rb @@ -7,14 +7,8 @@ class Registrar authorize! :manage, :repp uri = BASE_URL - request = Net::HTTP::Patch.new(uri) - request.set_form_data(current_contact_id: params[:current_contact_id], - new_contact_id: params[:new_contact_id]) - request.basic_auth(current_registrar_user.username, - current_registrar_user.plain_text_password) - + request = form_request(uri) response = do_request(request, uri) - start_notice = t('.replaced') process_response(response: response, diff --git a/app/views/registrar/bulk_change/_admin_contact_form.html.erb b/app/views/registrar/bulk_change/_admin_contact_form.html.erb new file mode 100644 index 000000000..d8b4beb55 --- /dev/null +++ b/app/views/registrar/bulk_change/_admin_contact_form.html.erb @@ -0,0 +1,60 @@ +<%= form_tag registrar_admin_contacts_path, method: :patch, class: 'form-horizontal' do %> + <% if @error %> +
+ <%= @error %> +
+ <% end %> + +
+
+ <%= label_tag :current_contact_id, t('.current_contact_id') %> +
+ +
+ <%= text_field_tag :current_contact_id, params[:current_contact_id], + list: :contacts, + required: true, + autofocus: true, + class: 'form-control' %> +
+
+ +
+
+ <%= label_tag :new_contact_id, t('.new_contact_id') %> +
+ +
+ <%= text_field_tag :new_contact_id, params[:new_contact_id], + list: :contacts, + required: true, + class: 'form-control' %> +
+
+ +
+
+ +
+
+ +
+
+ <%= t '.help_btn' %> +
+
+ <%= t '.help' %> +
+
+
+
+<% end %> + + + <% available_contacts.each do |data| %> + + <% end %> + diff --git a/app/views/registrar/bulk_change/new.html.erb b/app/views/registrar/bulk_change/new.html.erb index e61270b6d..f3095a53d 100644 --- a/app/views/registrar/bulk_change/new.html.erb +++ b/app/views/registrar/bulk_change/new.html.erb @@ -12,6 +12,10 @@ <%= t '.technical_contact' %> +
  • + <%= t '.admin_contact' %> +
  • +
  • <%= t '.nameserver' %>
  • @@ -31,6 +35,11 @@ <%= render 'tech_contact_form', available_contacts: available_contacts %> +
    + <%= render 'admin_contact_form', available_contacts: available_contacts %> +
    +
    <%= render 'nameserver_form' %>
    diff --git a/config/locales/registrar/admin_contacts.en.yml b/config/locales/registrar/admin_contacts.en.yml new file mode 100644 index 000000000..9265a6d10 --- /dev/null +++ b/config/locales/registrar/admin_contacts.en.yml @@ -0,0 +1,6 @@ +en: + registrar: + admin_contacts: + update: + replaced: Admin contacts have been successfully replaced. + replaced: Technical contacts have been successfully replaced. diff --git a/config/locales/registrar/bulk_change.en.yml b/config/locales/registrar/bulk_change.en.yml index 58d5fce97..6bd7fd84c 100644 --- a/config/locales/registrar/bulk_change.en.yml +++ b/config/locales/registrar/bulk_change.en.yml @@ -18,6 +18,16 @@ en: Replace technical contact specified in "current contact ID" with the one in "new contact ID" on any domain registered under this registrar + admin_contact_form: + current_contact_id: Current admin contact ID + new_contact_id: New admin contact ID + submit_btn: Replace admin contacts + help_btn: Toggle help + help: >- + Replace admin contact specified in "current contact ID" with the one in "new + contact ID" on any domain registered under this registrar. Contact idents must + be the same + nameserver_form: ip_hint: One IP per line replace_btn: Replace nameserver diff --git a/config/routes.rb b/config/routes.rb index 16102f2b6..2c9590477 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -137,6 +137,7 @@ Rails.application.routes.draw do resource :bulk_change, controller: :bulk_change, only: :new post '/bulk_renew/new', to: 'bulk_change#bulk_renew', as: :bulk_renew resource :tech_contacts, only: :update + resource :admin_contacts, only: :update resource :nameservers, only: :update resources :contacts, constraints: {:id => /[^\/]+(?=#{ ActionController::Renderers::RENDERERS.map{|e| "\\.#{e}\\z"}.join("|") })|[^\/]+/} do member do From e5c41cf531d99137e68abfd3ad463ecfbf646475 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 8 Feb 2021 14:53:54 +0500 Subject: [PATCH 28/37] Fix tests --- .../registrar/bulk_change/_admin_contact_form.html.erb | 4 ++-- .../registrar/bulk_change/_tech_contact_form.html.erb | 4 ++-- .../registrar_area/bulk_change/tech_contact_test.rb | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/views/registrar/bulk_change/_admin_contact_form.html.erb b/app/views/registrar/bulk_change/_admin_contact_form.html.erb index d8b4beb55..bb682aa60 100644 --- a/app/views/registrar/bulk_change/_admin_contact_form.html.erb +++ b/app/views/registrar/bulk_change/_admin_contact_form.html.erb @@ -10,7 +10,7 @@ <%= label_tag :current_contact_id, t('.current_contact_id') %> -
    +
    <%= text_field_tag :current_contact_id, params[:current_contact_id], list: :contacts, required: true, @@ -24,7 +24,7 @@ <%= label_tag :new_contact_id, t('.new_contact_id') %>
    -
    +
    <%= text_field_tag :new_contact_id, params[:new_contact_id], list: :contacts, required: true, diff --git a/app/views/registrar/bulk_change/_tech_contact_form.html.erb b/app/views/registrar/bulk_change/_tech_contact_form.html.erb index 2848e3634..789db92ba 100644 --- a/app/views/registrar/bulk_change/_tech_contact_form.html.erb +++ b/app/views/registrar/bulk_change/_tech_contact_form.html.erb @@ -10,7 +10,7 @@ <%= label_tag :current_contact_id, t('.current_contact_id') %>
    -
    +
    <%= text_field_tag :current_contact_id, params[:current_contact_id], list: :contacts, required: true, @@ -24,7 +24,7 @@ <%= label_tag :new_contact_id, t('.new_contact_id') %>
    -
    +
    <%= text_field_tag :new_contact_id, params[:new_contact_id], list: :contacts, required: true, diff --git a/test/system/registrar_area/bulk_change/tech_contact_test.rb b/test/system/registrar_area/bulk_change/tech_contact_test.rb index e08457f60..055ec25ca 100644 --- a/test/system/registrar_area/bulk_change/tech_contact_test.rb +++ b/test/system/registrar_area/bulk_change/tech_contact_test.rb @@ -16,8 +16,8 @@ class RegistrarAreaTechContactBulkChangeTest < ApplicationSystemTestCase visit registrar_domains_url click_link 'Bulk change' - fill_in 'Current contact ID', with: 'william-001' - fill_in 'New contact ID', with: 'john-001' + find('.current_tech_contact').fill_in 'Current contact ID', with: 'william-001' + find('.new_tech_contact').fill_in 'New contact ID', with: 'john-001' click_on 'Replace technical contacts' assert_requested request_stub @@ -36,8 +36,8 @@ class RegistrarAreaTechContactBulkChangeTest < ApplicationSystemTestCase visit registrar_domains_url click_link 'Bulk change' - fill_in 'Current contact ID', with: 'william-001' - fill_in 'New contact ID', with: 'john-001' + find('.current_tech_contact').fill_in 'Current contact ID', with: 'william-001' + find('.new_tech_contact').fill_in 'New contact ID', with: 'john-001' click_on 'Replace technical contacts' assert_text 'epic fail' From 9611df92b0f0f1a86cddd05069dd9211144d2941 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 8 Feb 2021 15:35:46 +0500 Subject: [PATCH 29/37] Add system test & fix locale --- .../registrar/admin_contacts_controller.rb | 1 - config/locales/registrar/admin_contacts.yml | 11 +++++ .../bulk_change/admin_contact_test.rb | 49 +++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 config/locales/registrar/admin_contacts.yml create mode 100644 test/system/registrar_area/bulk_change/admin_contact_test.rb diff --git a/app/controllers/registrar/admin_contacts_controller.rb b/app/controllers/registrar/admin_contacts_controller.rb index 55cfbae9e..a1400b6dc 100644 --- a/app/controllers/registrar/admin_contacts_controller.rb +++ b/app/controllers/registrar/admin_contacts_controller.rb @@ -5,7 +5,6 @@ class Registrar def update authorize! :manage, :repp - uri = BASE_URL request = form_request(uri) response = do_request(request, uri) diff --git a/config/locales/registrar/admin_contacts.yml b/config/locales/registrar/admin_contacts.yml new file mode 100644 index 000000000..d258b4275 --- /dev/null +++ b/config/locales/registrar/admin_contacts.yml @@ -0,0 +1,11 @@ +en: + registrar: + admin_contacts: + update: + replaced: Admin contacts have been successfully replaced. + affected_domains: Affected domains + skipped_domains: Skipped domains + process_request: + affected_domains: Affected domains + skipped_domains: Skipped domains + replaced: Admin contacts have been successfully replaced. diff --git a/test/system/registrar_area/bulk_change/admin_contact_test.rb b/test/system/registrar_area/bulk_change/admin_contact_test.rb new file mode 100644 index 000000000..8847812cb --- /dev/null +++ b/test/system/registrar_area/bulk_change/admin_contact_test.rb @@ -0,0 +1,49 @@ +require 'application_system_test_case' + +class RegistrarAreaAdminContactBulkChangeTest < ApplicationSystemTestCase + setup do + sign_in users(:api_bestnames) + end + + def test_replace_domain_contacts_of_current_registrar + request_stub = stub_request(:patch, /domains\/admin_contacts/) + .with(body: { current_contact_id: 'william-001', new_contact_id: 'john-001' }, + basic_auth: ['test_bestnames', 'testtest']) + .to_return(body: { data: { affected_domains: %w[foo.test bar.test], + skipped_domains: %w[baz.test qux.test] } }.to_json, + status: 200) + + visit registrar_domains_url + click_link 'Bulk change' + click_link 'Admin contact' + + find('.current_admin_contact').fill_in 'Current contact ID', with: 'william-001' + find('.new_admin_contact').fill_in 'New contact ID', with: 'john-001' + click_on 'Replace admin contacts' + + assert_requested request_stub + assert_current_path registrar_domains_path + assert_text 'Admin contacts have been successfully replaced' + assert_text 'Affected domains: foo.test, bar.test' + assert_text 'Skipped domains: baz.test, qux.test' + end + + def test_fails_gracefully + stub_request(:patch, /domains\/admin_contacts/) + .to_return(status: 400, + body: { message: 'epic fail' }.to_json, + headers: { 'Content-type' => Mime[:json] }) + + visit registrar_domains_url + click_link 'Bulk change' + click_link 'Admin contact' + + find('.current_admin_contact').fill_in 'Current contact ID', with: 'william-001' + find('.new_admin_contact').fill_in 'New contact ID', with: 'john-001' + click_on 'Replace admin contacts' + + assert_text 'epic fail' + assert_field 'Current contact ID', with: 'william-001' + assert_field 'New contact ID', with: 'john-001' + end +end From 6304ebdbc63605fa152b47966dc64fcab040301a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 8 Feb 2021 16:28:04 +0200 Subject: [PATCH 30/37] Add Amazon SDK gem --- Gemfile | 2 ++ Gemfile.lock | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/Gemfile b/Gemfile index dd879a11b..2d156c829 100644 --- a/Gemfile +++ b/Gemfile @@ -92,3 +92,5 @@ group :test do gem 'webdrivers' gem 'webmock' end + +gem "aws-sdk-ses", "~> 1.37" diff --git a/Gemfile.lock b/Gemfile.lock index 51c880c9e..01408ebd7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -148,6 +148,18 @@ GEM attr_required (1.0.1) autoprefixer-rails (10.0.0.2) execjs + aws-eventstream (1.1.0) + aws-partitions (1.424.0) + aws-sdk-core (3.112.0) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.239.0) + aws-sigv4 (~> 1.1) + jmespath (~> 1.0) + aws-sdk-ses (1.37.0) + aws-sdk-core (~> 3, >= 3.112.0) + aws-sigv4 (~> 1.1) + aws-sigv4 (1.2.2) + aws-eventstream (~> 1, >= 1.0.2) bcrypt (3.1.16) bindata (2.4.8) bootsnap (1.4.8) @@ -226,6 +238,7 @@ GEM i18n_data (0.10.0) isikukood (0.1.2) iso8601 (0.12.1) + jmespath (1.4.0) jquery-rails (4.4.0) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) @@ -484,6 +497,7 @@ DEPENDENCIES active_interaction (~> 3.8) activerecord-import airbrake + aws-sdk-ses (~> 1.37) bootsnap (>= 1.1.0) bootstrap-sass (~> 3.4) cancancan From 2af0bfdda04f5427080385507f2faf8a31e7e783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 8 Feb 2021 16:52:31 +0200 Subject: [PATCH 31/37] BouncedMailAddress: Remove from AWS suppression list upon destroy --- Gemfile | 2 +- Gemfile.lock | 4 ++-- app/models/bounced_mail_address.rb | 17 +++++++++++++++++ config/initializers/aws_ses.rb | 4 ++++ 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 config/initializers/aws_ses.rb diff --git a/Gemfile b/Gemfile index 2d156c829..79862bd69 100644 --- a/Gemfile +++ b/Gemfile @@ -93,4 +93,4 @@ group :test do gem 'webmock' end -gem "aws-sdk-ses", "~> 1.37" +gem "aws-sdk-sesv2", "~> 1.16" diff --git a/Gemfile.lock b/Gemfile.lock index 01408ebd7..08daf4226 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -155,7 +155,7 @@ GEM aws-partitions (~> 1, >= 1.239.0) aws-sigv4 (~> 1.1) jmespath (~> 1.0) - aws-sdk-ses (1.37.0) + aws-sdk-sesv2 (1.16.0) aws-sdk-core (~> 3, >= 3.112.0) aws-sigv4 (~> 1.1) aws-sigv4 (1.2.2) @@ -497,7 +497,7 @@ DEPENDENCIES active_interaction (~> 3.8) activerecord-import airbrake - aws-sdk-ses (~> 1.37) + aws-sdk-sesv2 (~> 1.16) bootsnap (>= 1.1.0) bootstrap-sass (~> 3.4) cancancan diff --git a/app/models/bounced_mail_address.rb b/app/models/bounced_mail_address.rb index 73c6a0941..d0411a6c9 100644 --- a/app/models/bounced_mail_address.rb +++ b/app/models/bounced_mail_address.rb @@ -1,5 +1,6 @@ class BouncedMailAddress < ApplicationRecord validates :email, :message_id, :bounce_type, :bounce_subtype, :action, :status, presence: true + after_destroy :destroy_aws_suppression def bounce_reason "#{action} (#{status} #{diagnostic})" @@ -25,4 +26,20 @@ class BouncedMailAddress < ApplicationRecord diagnostic: bounced_record['diagnosticCode'], } end + + def destroy_aws_suppression + return unless BouncedMailAddress.ses_configured? + + res = Aws::SESV2::Client.new.delete_suppressed_destination({ email_address: email }) + res.successful? + rescue Aws::SESV2::Errors::ServiceError => e + logger.warn("Suppression not removed. #{e}") + end + + def self.ses_configured? + ses ||= Aws::SES::Client.new + ses.config.credentials.access_key_id.present? + rescue Aws::Errors::MissingRegionError + false + end end diff --git a/config/initializers/aws_ses.rb b/config/initializers/aws_ses.rb new file mode 100644 index 000000000..baa148e65 --- /dev/null +++ b/config/initializers/aws_ses.rb @@ -0,0 +1,4 @@ +Aws.config.update( + region: ENV['aws_default_region'], + credentials: Aws::Credentials.new(ENV['aws_access_key_id'], ENV['aws_secret_access_key']) +) From f6fd10b01767bb3aa0421200ef9901ad0d387042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 8 Feb 2021 16:57:16 +0200 Subject: [PATCH 32/37] Fix CC issues --- Gemfile | 2 +- app/models/bounced_mail_address.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 79862bd69..82a0b4666 100644 --- a/Gemfile +++ b/Gemfile @@ -93,4 +93,4 @@ group :test do gem 'webmock' end -gem "aws-sdk-sesv2", "~> 1.16" +gem 'aws-sdk-sesv2', '~> 1.16' diff --git a/app/models/bounced_mail_address.rb b/app/models/bounced_mail_address.rb index d0411a6c9..db4413829 100644 --- a/app/models/bounced_mail_address.rb +++ b/app/models/bounced_mail_address.rb @@ -30,14 +30,14 @@ class BouncedMailAddress < ApplicationRecord def destroy_aws_suppression return unless BouncedMailAddress.ses_configured? - res = Aws::SESV2::Client.new.delete_suppressed_destination({ email_address: email }) + res = Aws::SESV2::Client.new.delete_suppressed_destination(email_address: email) res.successful? rescue Aws::SESV2::Errors::ServiceError => e logger.warn("Suppression not removed. #{e}") end def self.ses_configured? - ses ||= Aws::SES::Client.new + ses ||= Aws::SESV2::Client.new ses.config.credentials.access_key_id.present? rescue Aws::Errors::MissingRegionError false From b892927f11c98b961cae8d33ee3daa605a966600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Tue, 9 Feb 2021 16:12:57 +0200 Subject: [PATCH 33/37] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 064905ba7..891059845 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +09.02.2021 +* Added new endpoint for WHOIS contact requests [#1794](https://github.com/internetee/registry/pull/1794) + 05.02.2021 * Fixed IPv4 empty string issue in case of IPv6 only entries for IP whitelist [#1833](https://github.com/internetee/registry/issues/1833) From 1b6c4516564343679715fc852aecb7db4987739b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 10 Feb 2021 12:17:32 +0200 Subject: [PATCH 34/37] Create separate key for Bounces API --- app/controllers/api/v1/base_controller.rb | 2 +- app/controllers/api/v1/bounces_controller.rb | 9 ++++++++- config/application.yml.sample | 6 +++--- test/integration/api/v1/bounces/create_test.rb | 2 +- test/integration/api/v1/contact_requests_test.rb | 2 +- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/v1/base_controller.rb b/app/controllers/api/v1/base_controller.rb index 045e4395e..6ee986a48 100644 --- a/app/controllers/api/v1/base_controller.rb +++ b/app/controllers/api/v1/base_controller.rb @@ -11,7 +11,7 @@ module Api end def authenticate_shared_key - api_key = "Basic #{ENV['internal_api_key']}" + api_key = "Basic #{ENV['rwhois_internal_api_shared_key']}" head(:unauthorized) unless api_key == request.authorization end diff --git a/app/controllers/api/v1/bounces_controller.rb b/app/controllers/api/v1/bounces_controller.rb index fd10a3398..de2814250 100644 --- a/app/controllers/api/v1/bounces_controller.rb +++ b/app/controllers/api/v1/bounces_controller.rb @@ -1,7 +1,7 @@ module Api module V1 class BouncesController < BaseController - before_action :authenticate_shared_key + before_action :validate_shared_key_integrity # POST api/v1/bounces/ def create @@ -20,6 +20,13 @@ module Api params.require(:data) end + + private + + def validate_shared_key_integrity + api_key = "Basic #{ENV['rwhois_bounces_api_shared_key']}" + head(:unauthorized) unless api_key == request.authorization + end end end end diff --git a/config/application.yml.sample b/config/application.yml.sample index 21f1df8e0..dd38e206c 100644 --- a/config/application.yml.sample +++ b/config/application.yml.sample @@ -87,11 +87,11 @@ sk_digi_doc_service_name: 'Testimine' registrant_api_base_url: registrant_api_auth_allowed_ips: '127.0.0.1, 0.0.0.0' #ips, separated with commas -# Bounces API -api_shared_key: testkey +# Shared key for REST-WHOIS Bounces API incl. CERT +rwhois_bounces_api_shared_key: testkey # Link to REST-WHOIS API -internal_api_key: testkey +rwhois_internal_api_shared_key: testkey # Base URL (inc. https://) of REST registrant portal # Leave blank to use internal registrant portal diff --git a/test/integration/api/v1/bounces/create_test.rb b/test/integration/api/v1/bounces/create_test.rb index 899b6c5c7..0d3dc65d7 100644 --- a/test/integration/api/v1/bounces/create_test.rb +++ b/test/integration/api/v1/bounces/create_test.rb @@ -2,7 +2,7 @@ require 'test_helper' class BouncesApiV1CreateTest < ActionDispatch::IntegrationTest def setup - @api_key = "Basic #{ENV['api_shared_key']}" + @api_key = "Basic #{ENV['rwhois_bounces_api_shared_key']}" @headers = { "Authorization": "#{@api_key}" } @json_body = { "data": valid_bounce_request }.as_json end diff --git a/test/integration/api/v1/contact_requests_test.rb b/test/integration/api/v1/contact_requests_test.rb index f0621b686..c9e2ac9bd 100644 --- a/test/integration/api/v1/contact_requests_test.rb +++ b/test/integration/api/v1/contact_requests_test.rb @@ -2,7 +2,7 @@ require 'test_helper' class ApiV1ContactRequestTest < ActionDispatch::IntegrationTest def setup - @api_key = "Basic #{ENV['api_shared_key']}" + @api_key = "Basic #{ENV['rwhois_internal_api_shared_key']}" @headers = { "Authorization": "#{@api_key}" } @json_create = { "contact_request": valid_contact_request_create }.as_json @json_update = { "contact_request": valid_contact_request_update }.as_json From 476093f3ce0a8741354160980a6189f376189146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Wed, 10 Feb 2021 14:14:23 +0200 Subject: [PATCH 35/37] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 891059845..6e53f4714 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +10.02.2021 +* Option to remove email addresses from AWS SES Supression list [#1839](https://github.com/internetee/registry/issues/1839) +* Added separate key for bounce API [#1842](https://github.com/internetee/registry/pull/1842) + 09.02.2021 * Added new endpoint for WHOIS contact requests [#1794](https://github.com/internetee/registry/pull/1794) From 4051c1941b4e861bee9a406829243aba70b7c7cf Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Wed, 10 Feb 2021 19:57:39 +0500 Subject: [PATCH 36/37] Add a commenting message to UI form --- app/views/registrar/bulk_change/_admin_contact_form.html.erb | 5 +++++ config/locales/registrar/bulk_change.en.yml | 3 +++ 2 files changed, 8 insertions(+) diff --git a/app/views/registrar/bulk_change/_admin_contact_form.html.erb b/app/views/registrar/bulk_change/_admin_contact_form.html.erb index bb682aa60..77734e872 100644 --- a/app/views/registrar/bulk_change/_admin_contact_form.html.erb +++ b/app/views/registrar/bulk_change/_admin_contact_form.html.erb @@ -6,6 +6,11 @@ <% end %>
    +
    +
    +

    <%= t '.comment' %>

    +
    +
    <%= label_tag :current_contact_id, t('.current_contact_id') %>
    diff --git a/config/locales/registrar/bulk_change.en.yml b/config/locales/registrar/bulk_change.en.yml index 6bd7fd84c..d9f6ebbd2 100644 --- a/config/locales/registrar/bulk_change.en.yml +++ b/config/locales/registrar/bulk_change.en.yml @@ -27,6 +27,9 @@ en: Replace admin contact specified in "current contact ID" with the one in "new contact ID" on any domain registered under this registrar. Contact idents must be the same + comment: >- + Bulk admin change is only allowed in case of old and new contact are sharing identical + ident data ie for updating contact information. nameserver_form: ip_hint: One IP per line From 7063aa1210cd488ee99c38da2a4e2d78f2e0486e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Wed, 10 Feb 2021 17:04:08 +0200 Subject: [PATCH 37/37] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e53f4714..7f6065826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ 10.02.2021 +* Admin contact bulk change option for registrars [#1764](https://github.com/internetee/registry/issues/1764) * Option to remove email addresses from AWS SES Supression list [#1839](https://github.com/internetee/registry/issues/1839) * Added separate key for bounce API [#1842](https://github.com/internetee/registry/pull/1842)