Merge remote-tracking branch 'origin/master' into 1819-improve-credit-account-balance-overview

This commit is contained in:
Karl Erik Õunapuu 2021-02-12 11:30:09 +02:00
commit 9a7acf7c33
No known key found for this signature in database
GPG key ID: C9DD647298A34764
93 changed files with 2337 additions and 203 deletions

View file

@ -7,14 +7,19 @@ prepare:
plugins: plugins:
brakeman: brakeman:
enabled: true enabled: true
checks:
mass_assign_permit!:
enabled: false
bundler-audit: bundler-audit:
enabled: true enabled: true
duplication: duplication:
enabled: true enabled: true
config: config:
languages: languages:
- ruby ruby:
- javascript mass_threshold: 100
javascript:
mass_threshold: 100
eslint: eslint:
enabled: true enabled: true
channel: eslint-5 channel: eslint-5

View file

@ -1,3 +1,36 @@
11.02.2021
* Poll messages on locking and unlocking a domain [#1828](https://github.com/internetee/registry/issues/1828)
* Registrar's prefix is now checked and added to contact id for info and check requests [#1832](https://github.com/internetee/registry/issues/1832)
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)
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)
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)
28.01.2021
* Fixed transfer with shared admin and tech contacts [#1808](https://github.com/internetee/registry/issues/1808)
* Improved error handling with double admin/tech contacts [#1758](https://github.com/internetee/registry/issues/1758)
* Added CSV export option to admin [#1775](https://github.com/internetee/registry/issues/1775)
* Improved DNSSEC key validation for illegal characters [#1790](https://github.com/internetee/registry/issues/1790)
* Fix for whois record creation issue on releasing domain to auction [#1139](https://github.com/internetee/registry/issues/1139)
* Fix for handling malformed request frames [#1825](https://github.com/internetee/registry/issues/1825)
* Improved registrar account activity tests [#1824](https://github.com/internetee/registry/pull/1824)
27.01.2021
* Figaro update to 1.2.0 [#1823](https://github.com/internetee/registry/pull/1823)
26.01.2021 26.01.2021
* Ruby update to 2.7 [#1791](https://github.com/internetee/registry/issues/1791) * Ruby update to 2.7 [#1791](https://github.com/internetee/registry/issues/1791)

View file

@ -9,7 +9,7 @@ gem 'rest-client'
gem 'uglifier' gem 'uglifier'
# load env # load env
gem 'figaro', '1.1.1' gem 'figaro', '~> 1.2'
# model related # model related
gem 'activerecord-import' gem 'activerecord-import'
@ -92,3 +92,5 @@ group :test do
gem 'webdrivers' gem 'webdrivers'
gem 'webmock' gem 'webmock'
end end
gem 'aws-sdk-sesv2', '~> 1.16'

View file

@ -148,6 +148,18 @@ GEM
attr_required (1.0.1) attr_required (1.0.1)
autoprefixer-rails (10.0.0.2) autoprefixer-rails (10.0.0.2)
execjs 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-sesv2 (1.16.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) bcrypt (3.1.16)
bindata (2.4.8) bindata (2.4.8)
bootsnap (1.4.8) bootsnap (1.4.8)
@ -202,8 +214,8 @@ GEM
erubis (2.7.0) erubis (2.7.0)
execjs (2.7.0) execjs (2.7.0)
ffi (1.13.1) ffi (1.13.1)
figaro (1.1.1) figaro (1.2.0)
thor (~> 0.14) thor (>= 0.14.0, < 2)
globalid (0.4.2) globalid (0.4.2)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
gyoku (1.3.1) gyoku (1.3.1)
@ -226,6 +238,7 @@ GEM
i18n_data (0.10.0) i18n_data (0.10.0)
isikukood (0.1.2) isikukood (0.1.2)
iso8601 (0.12.1) iso8601 (0.12.1)
jmespath (1.4.0)
jquery-rails (4.4.0) jquery-rails (4.4.0)
rails-dom-testing (>= 1, < 3) rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0) railties (>= 4.2.0)
@ -484,6 +497,7 @@ DEPENDENCIES
active_interaction (~> 3.8) active_interaction (~> 3.8)
activerecord-import activerecord-import
airbrake airbrake
aws-sdk-sesv2 (~> 1.16)
bootsnap (>= 1.1.0) bootsnap (>= 1.1.0)
bootstrap-sass (~> 3.4) bootstrap-sass (~> 3.4)
cancancan cancancan
@ -502,7 +516,7 @@ DEPENDENCIES
e_invoice! e_invoice!
epp! epp!
epp-xml (= 1.1.0)! epp-xml (= 1.1.0)!
figaro (= 1.1.1) figaro (~> 1.2)
haml (~> 5.0) haml (~> 5.0)
isikukood isikukood
iso8601 (= 0.12.1) iso8601 (= 0.12.1)

View file

@ -8,6 +8,8 @@ $(window).load ->
$('[data-toggle="popover"]').popover() $('[data-toggle="popover"]').popover()
$('[data-toggle="tooltip"]').tooltip()
# doublescroll # doublescroll
$('[data-doublescroll]').doubleScroll({ $('[data-doublescroll]').doubleScroll({
onlyIfScroll: false, onlyIfScroll: false,

View file

@ -27,8 +27,17 @@ module Admin
params[:q][:name_matches] = n_cache # we don't want to show wildcards in search form params[:q][:name_matches] = n_cache # we don't want to show wildcards in search form
end end
end end
@domains = @domains.per(params[:results_per_page]) if params[:results_per_page].to_i.positive? @domains = @domains.per(params[:results_per_page]) if params[:results_per_page].to_i.positive?
respond_to do |format|
format.html do
@domains
end
format.csv do
raw_csv = @domains.to_csv
send_data raw_csv, filename: 'domains.csv', type: "#{Mime[:csv]}; charset=utf-8"
end
end
end end
def show def show

View file

@ -11,7 +11,7 @@ module Api
end end
def authenticate_shared_key def authenticate_shared_key
api_key = "Basic #{ENV['api_shared_key']}" api_key = "Basic #{ENV['rwhois_internal_api_shared_key']}"
head(:unauthorized) unless api_key == request.authorization head(:unauthorized) unless api_key == request.authorization
end end

View file

@ -1,7 +1,7 @@
module Api module Api
module V1 module V1
class BouncesController < BaseController class BouncesController < BaseController
before_action :authenticate_shared_key before_action :validate_shared_key_integrity
# POST api/v1/bounces/ # POST api/v1/bounces/
def create def create
@ -20,6 +20,13 @@ module Api
params.require(:data) params.require(:data)
end 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 end
end end

View file

@ -0,0 +1,37 @@
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?
contact_request = ContactRequest.save_record(contact_request_params)
render json: contact_request, status: :created
rescue StandardError
head(:bad_request)
end
def update
return head(:bad_request) if params[:id].blank?
process_id(params[:id])
end
def process_id(id)
record = ContactRequest.find_by(id: id)
return :not_found unless record
record.update_status(contact_request_params)
render json: record, status: :ok
rescue StandardError
head :bad_request
end
def contact_request_params
params.require(:contact_request).permit(:email, :whois_record_id, :name, :status, :ip)
end
end
end
end

View file

@ -14,7 +14,7 @@ module Epp
authorize! :check, Epp::Contact authorize! :check, Epp::Contact
ids = params[:parsed_frame].css('id').map(&:text) ids = params[:parsed_frame].css('id').map(&:text)
@results = Epp::Contact.check_availability(ids) @results = Epp::Contact.check_availability(ids, reg: current_user.registrar.code)
render_epp_response '/epp/contacts/check' render_epp_response '/epp/contacts/check'
end end
@ -93,7 +93,11 @@ module Epp
def find_contact def find_contact
code = params[:parsed_frame].css('id').text.strip.upcase code = params[:parsed_frame].css('id').text.strip.upcase
@contact = Epp::Contact.find_by!(code: code) reg_code = current_user.registrar.code.upcase
arr = [code, "#{reg_code}:#{code}", "CID:#{code}", "CID:#{reg_code}:#{code}"]
contact = arr.find { |c| Epp::Contact.find_by(code: c).present? }
@contact = Epp::Contact.find_by!(code: contact || code)
end end
# #

View file

@ -0,0 +1,18 @@
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

View file

@ -26,6 +26,84 @@ class Registrar
private 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)
if response.code == '200'
notices = success_notices(parsed_response, start_notice)
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: active_tab }
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)
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? def ready_to_renew?
domain_ids_for_bulk_renew.present? && params[:renew].present? domain_ids_for_bulk_renew.present? && params[:renew].present?
end end

View file

@ -25,32 +25,7 @@ class Registrar
current_registrar_user.plain_text_password) current_registrar_user.plain_text_password)
if Rails.env.test? response = do_request(request, uri)
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
parsed_response = JSON.parse(response.body, symbolize_names: true) parsed_response = JSON.parse(response.body, symbolize_names: true)

View file

@ -18,32 +18,7 @@ class Registrar
request.basic_auth(current_registrar_user.username, request.basic_auth(current_registrar_user.username,
current_registrar_user.plain_text_password) current_registrar_user.plain_text_password)
if Rails.env.test? response = do_request(request, uri)
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
parsed_response = JSON.parse(response.body, symbolize_names: true) parsed_response = JSON.parse(response.body, symbolize_names: true)

View file

@ -1,62 +1,19 @@
class Registrar class Registrar
class TechContactsController < BulkChangeController class TechContactsController < BulkChangeController
BASE_URL = URI.parse("#{ENV['repp_url']}domains/contacts").freeze
ACTIVE_TAB = :technical_contact
def update def update
authorize! :manage, :repp authorize! :manage, :repp
uri = URI.parse("#{ENV['repp_url']}domains/contacts") uri = BASE_URL
request = form_request(uri)
response = do_request(request, uri)
start_notice = t('.replaced')
request = Net::HTTP::Patch.new(uri) process_response(response: response,
request.set_form_data(current_contact_id: params[:current_contact_id], start_notice: start_notice,
new_contact_id: params[:new_contact_id]) active_tab: ACTIVE_TAB)
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
parsed_response = JSON.parse(response.body, symbolize_names: true)
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
end end
end end
end end

View file

@ -0,0 +1,21 @@
module Repp
module V1
module Domains
class AdminContactsController < BaseContactsController
def update
super
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
end
end
end
end

View file

@ -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

View file

@ -1,23 +1,9 @@
module Repp module Repp
module V1 module V1
module Domains module Domains
class ContactsController < BaseController class ContactsController < BaseContactsController
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 def update
@epp_errors ||= [] super
@epp_errors << { code: 2304, msg: 'New contact must be valid' } if @new_contact.invalid?
if @new_contact == @current_contact if @new_contact == @current_contact
@epp_errors << { code: 2304, msg: 'New contact must be different from current' } @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 } @response = { affected_domains: affected, skipped_domains: skipped }
render_success(data: @response) render_success(data: @response)
end 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
end end

6
app/lib/to_stdout.rb Normal file
View file

@ -0,0 +1,6 @@
class ToStdout
def self.msg(message)
time = Time.zone.now.utc
STDOUT << "#{time} - #{message}\n" unless Rails.env.test?
end
end

View file

@ -1,2 +1,26 @@
class AdminDomainContact < DomainContact class AdminDomainContact < DomainContact
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
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.bulk_update_prohibited?
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
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength
end end

View file

@ -1,5 +1,6 @@
class BouncedMailAddress < ApplicationRecord class BouncedMailAddress < ApplicationRecord
validates :email, :message_id, :bounce_type, :bounce_subtype, :action, :status, presence: true validates :email, :message_id, :bounce_type, :bounce_subtype, :action, :status, presence: true
after_destroy :destroy_aws_suppression
def bounce_reason def bounce_reason
"#{action} (#{status} #{diagnostic})" "#{action} (#{status} #{diagnostic})"
@ -25,4 +26,20 @@ class BouncedMailAddress < ApplicationRecord
diagnostic: bounced_record['diagnosticCode'], diagnostic: bounced_record['diagnosticCode'],
} }
end 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::SESV2::Client.new
ses.config.credentials.access_key_id.present?
rescue Aws::Errors::MissingRegionError
false
end
end end

View file

@ -11,6 +11,13 @@ module Concerns::Contact::Identical
ident_country_code ident_country_code
org_name org_name
] ]
IDENTICAL_ATTRIBUTES = %w[
ident
ident_type
ident_country_code
].freeze
private_constant :IDENTIFIABLE_ATTRIBUTES private_constant :IDENTIFIABLE_ATTRIBUTES
def identical(registrar) def identical(registrar)
@ -20,6 +27,12 @@ module Concerns::Contact::Identical
.where.not(id: id).take .where.not(id: id).take
end end
def identical_to?(contact)
IDENTICAL_ATTRIBUTES.all? do |attribute|
attributes[attribute] == contact.attributes[attribute]
end
end
private private
def identifiable_hash def identifiable_hash

View file

@ -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

View file

@ -12,6 +12,7 @@ module Concerns
statuses << DomainStatus::SERVER_DELETE_PROHIBITED statuses << DomainStatus::SERVER_DELETE_PROHIBITED
statuses << DomainStatus::SERVER_TRANSFER_PROHIBITED statuses << DomainStatus::SERVER_TRANSFER_PROHIBITED
self.locked_by_registrant_at = Time.zone.now self.locked_by_registrant_at = Time.zone.now
alert_registrar_lock_changes!(lock: true)
save! save!
end end
@ -42,10 +43,21 @@ module Concerns
statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED) statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED)
statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED) statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED)
self.locked_by_registrant_at = nil self.locked_by_registrant_at = nil
alert_registrar_lock_changes!(lock: false)
save! save!
end end
end end
def alert_registrar_lock_changes!(lock: true)
translation = lock ? 'locked' : 'unlocked'
registrar.notifications.create!(
text: I18n.t("notifications.texts.registrar_#{translation}",
domain_name: name),
attached_obj_id: name,
attached_obj_type: self.class.name
)
end
end end
end end
end end

View file

@ -39,13 +39,15 @@ module Concerns
def release def release
if release_to_auction if release_to_auction
transaction do ToStdout.msg 'Destroying domain'
domain_name.sell_at_auction if domain_name.auctionable? destroy!
destroy! ToStdout.msg "Checking if domain_name is auctionable: #{domain_name.auctionable?}"
registrar.notifications.create!(text: "#{I18n.t(:domain_deleted)}: #{name}", domain_name.sell_at_auction if domain_name.auctionable?
attached_obj_id: id,
attached_obj_type: self.class) ToStdout.msg 'Sending registrar notification'
end registrar.notifications.create!(text: "#{I18n.t(:domain_deleted)}: #{name}",
attached_obj_id: id,
attached_obj_type: self.class)
else else
discard discard
end end

View file

@ -59,7 +59,7 @@ module Concerns::Domain::Transferable
copied_ids = [] copied_ids = []
domain_contacts.each do |dc| domain_contacts.each do |dc|
contact = Contact.find(dc.contact_id) contact = Contact.find(dc.contact_id)
next if copied_ids.include?(contact.id) || contact.registrar == new_registrar next if copied_ids.include?(uniq_contact_hash(dc)) || contact.registrar == new_registrar
if registrant_id_was == contact.id # registrant was copied previously, do not copy it again if registrant_id_was == contact.id # registrant was copied previously, do not copy it again
oc = OpenStruct.new(id: registrant_id) oc = OpenStruct.new(id: registrant_id)
@ -72,7 +72,11 @@ module Concerns::Domain::Transferable
else else
dc.update(contact_id: oc.id) dc.update(contact_id: oc.id)
end end
copied_ids << contact.id copied_ids << uniq_contact_hash(dc)
end end
end end
def uniq_contact_hash(contact)
Digest::SHA1.hexdigest(contact.contact_id.to_s + contact.type)
end
end end

View file

@ -0,0 +1,40 @@
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!
contact_request
end
def update_status(params)
self.status = params['status']
self.ip_address = params['ip']
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

View file

@ -36,6 +36,7 @@ module DNS
auction = Auction.new auction = Auction.new
auction.domain = name auction.domain = name
auction.start auction.start
ToStdout.msg "Created the auction: #{auction.inspect}"
update_whois_from_auction(auction) update_whois_from_auction(auction)
end end
@ -100,7 +101,8 @@ module DNS
whois_record = Whois::Record.find_or_create_by!(name: name) do |record| whois_record = Whois::Record.find_or_create_by!(name: name) do |record|
record.json = {} record.json = {}
end end
ToStdout.msg "Starting to update WHOIS record #{whois_record.inspect}\n\n"\
"from auction #{auction.inspect}"
whois_record.update_from_auction(auction) whois_record.update_from_auction(auction)
end end
end end

View file

@ -10,6 +10,7 @@ class Domain < ApplicationRecord
include Concerns::Domain::RegistryLockable include Concerns::Domain::RegistryLockable
include Concerns::Domain::Releasable include Concerns::Domain::Releasable
include Concerns::Domain::Disputable include Concerns::Domain::Disputable
include Concerns::Domain::BulkUpdatable
attr_accessor :roles attr_accessor :roles
@ -78,7 +79,7 @@ class Domain < ApplicationRecord
true true
end end
after_commit :update_whois_record, unless: -> { domain_name.at_auction? } after_commit :update_whois_record
after_create :update_reserved_domains after_create :update_reserved_domains
def update_reserved_domains def update_reserved_domains

View file

@ -42,17 +42,12 @@ class Epp::Contact < Contact
) )
end end
def check_availability(codes) def check_availability(codes, reg:)
codes = [codes] if codes.is_a?(String) codes = [codes] if codes.is_a?(String)
res = [] res = []
codes.each do |x| codes.map { |c| c.include?(':') ? c : "#{reg}:#{c}" }.map { |c| c.strip.upcase }.each do |x|
contact = find_by_epp_code(x) c = find_by_epp_code(x)
if contact res << (c ? { code: c.code, avail: 0, reason: 'in use' } : { code: x, avail: 1 })
res << { code: contact.code, avail: 0, reason: 'in use' }
else
res << { code: x, avail: 1 }
end
end end
res res

View file

@ -162,6 +162,9 @@ class Epp::Domain < Domain
at[:admin_domain_contacts_attributes] = admin_domain_contacts_attrs(frame, action) at[:admin_domain_contacts_attributes] = admin_domain_contacts_attrs(frame, action)
at[:tech_domain_contacts_attributes] = tech_domain_contacts_attrs(frame, action) at[:tech_domain_contacts_attributes] = tech_domain_contacts_attrs(frame, action)
check_for_same_contacts(at[:admin_domain_contacts_attributes], 'admin')
check_for_same_contacts(at[:tech_domain_contacts_attributes], 'tech')
pw = frame.css('authInfo > pw').text pw = frame.css('authInfo > pw').text
at[:transfer_code] = pw if pw.present? at[:transfer_code] = pw if pw.present?
@ -176,6 +179,11 @@ class Epp::Domain < Domain
at at
end end
def check_for_same_contacts(contacts, contact_type)
return unless contacts.uniq.count != contacts.count
add_epp_error('2306', contact_type, nil, %i[domain_contacts invalid])
end
# Adding legal doc to domain and # Adding legal doc to domain and
# if something goes wrong - raise Rollback error # if something goes wrong - raise Rollback error
@ -312,6 +320,7 @@ class Epp::Domain < Domain
keys = [] keys = []
return keys if frame.blank? return keys if frame.blank?
inf_data = DnsSecKeys.new(frame) inf_data = DnsSecKeys.new(frame)
add_epp_error('2005', nil, nil, %i[dnskeys invalid]) if not_base64?(inf_data)
if action == 'rem' && if action == 'rem' &&
frame.css('rem > all').first.try(:text) == 'true' frame.css('rem > all').first.try(:text) == 'true'
@ -333,6 +342,16 @@ class Epp::Domain < Domain
errors.any? ? [] : keys errors.any? ? [] : keys
end end
def not_base64?(inf_data)
inf_data.key_data.any? do |key|
value = key[:public_key]
!value.is_a?(String) || Base64.strict_encode64(Base64.strict_decode64(value)) != value
end
rescue ArgumentError
true
end
class DnsSecKeys class DnsSecKeys
def initialize(frame) def initialize(frame)
@key_data = [] @key_data = []
@ -381,7 +400,7 @@ class Epp::Domain < Domain
def key_data_from(frame) def key_data_from(frame)
xm_copy frame, KEY_INTERFACE xm_copy frame, KEY_INTERFACE
end end
def ds_data_from(frame) def ds_data_from(frame)
frame.css('dsData').each do |ds_data| frame.css('dsData').each do |ds_data|

View file

@ -25,6 +25,10 @@ class Notification < ApplicationRecord
'' ''
end end
def registry_lock?
text.include?('has been locked') || text.include?('has been unlocked')
end
private private
def set_defaults def set_defaults

View file

@ -6,7 +6,7 @@ class TechDomainContact < DomainContact
tech_contacts = where(contact: current_contact) tech_contacts = where(contact: current_contact)
tech_contacts.each do |tech_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 skipped_domains << tech_contact.domain.name
next next
end end
@ -18,7 +18,6 @@ class TechDomainContact < DomainContact
skipped_domains << tech_contact.domain.name skipped_domains << tech_contact.domain.name
end end
end end
[affected_domains.sort, skipped_domains.sort] [affected_domains.sort, skipped_domains.sort]
end end
end end

View file

@ -4,8 +4,13 @@ class WhiteIp < ApplicationRecord
validate :valid_ipv4? validate :valid_ipv4?
validate :valid_ipv6? validate :valid_ipv6?
validate :validate_ipv4_and_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 def validate_ipv4_and_ipv6
return if ipv4.present? || ipv6.present? return if ipv4.present? || ipv6.present?
errors.add(:base, I18n.t(:ipv4_or_ipv6_must_be_present)) errors.add(:base, I18n.t(:ipv4_or_ipv6_must_be_present))
@ -50,10 +55,10 @@ class WhiteIp < ApplicationRecord
def ids_including(ip) def ids_including(ip)
ipv4 = ipv6 = [] ipv4 = ipv6 = []
if check_ip4(ip).present? 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 end
if check_ip6(ip).present? 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 end
(ipv4 + ipv6).pluck(:id).flatten.uniq (ipv4 + ipv6).pluck(:id).flatten.uniq
end end

View file

@ -2,23 +2,34 @@ module Whois
class Record < Whois::Server class Record < Whois::Server
self.table_name = 'whois_records' self.table_name = 'whois_records'
def self.without_auctions
ids = Whois::Record.all.select { |record| Auction.where(domain: record.name).blank? }
.pluck(:id)
Whois::Record.where(id: ids)
end
def self.disclaimer def self.disclaimer
Setting.registry_whois_disclaimer Setting.registry_whois_disclaimer
end end
# rubocop:disable Metrics/AbcSize
def update_from_auction(auction) def update_from_auction(auction)
if auction.started? if auction.started?
update!(json: { name: auction.domain, update!(json: { name: auction.domain,
status: ['AtAuction'], status: ['AtAuction'],
disclaimer: self.class.disclaimer }) disclaimer: self.class.disclaimer })
ToStdout.msg "Updated from auction WHOIS record #{inspect}"
elsif auction.no_bids? elsif auction.no_bids?
ToStdout.msg "Destroying WHOIS record #{inspect}"
destroy! destroy!
elsif auction.awaiting_payment? || auction.payment_received? elsif auction.awaiting_payment? || auction.payment_received?
update!(json: { name: auction.domain, update!(json: { name: auction.domain,
status: ['PendingRegistration'], status: ['PendingRegistration'],
disclaimer: self.class.disclaimer, disclaimer: self.class.disclaimer,
registration_deadline: auction.whois_deadline }) registration_deadline: auction.whois_deadline })
ToStdout.msg "Updated from auction WHOIS record #{inspect}"
end end
end end
# rubocop:enable Metrics/AbcSize
end end
end end

View file

@ -97,7 +97,7 @@ class WhoisRecord < ApplicationRecord
end end
def destroy_whois_record def destroy_whois_record
Whois::Record.where(name: name).delete_all Whois::Record.without_auctions.where(name: name).delete_all
end end
private private

View file

@ -6,7 +6,7 @@
<%= f.search_field :name_matches, value: params[:q][:name_matches], class: 'form-control', placeholder: t(:name) %> <%= f.search_field :name_matches, value: params[:q][:name_matches], class: 'form-control', placeholder: t(:name) %>
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-2">
<div class="form-group"> <div class="form-group">
<%= f.label :registrant_ident, for: nil %> <%= f.label :registrant_ident, for: nil %>
<%= f.search_field :registrant_ident_eq, class: 'form-control', placeholder: t(:registrant_ident) %> <%= f.search_field :registrant_ident_eq, class: 'form-control', placeholder: t(:registrant_ident) %>
@ -18,7 +18,7 @@
<%= f.search_field :contacts_ident_eq, class: 'form-control', placeholder: t(:contact_ident) %> <%= f.search_field :contacts_ident_eq, class: 'form-control', placeholder: t(:contact_ident) %>
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-4">
<div class="form-group"> <div class="form-group">
<%= f.label :nameserver_hostname, for: nil %> <%= f.label :nameserver_hostname, for: nil %>
<%= f.search_field :nameservers_hostname_eq, class: 'form-control', placeholder: t(:nameserver_hostname) %> <%= f.search_field :nameservers_hostname_eq, class: 'form-control', placeholder: t(:nameserver_hostname) %>
@ -26,7 +26,7 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-5">
<div class="form-group"> <div class="form-group">
<%= f.label :registrar_name, for: nil %> <%= f.label :registrar_name, for: nil %>
<%= f.select :registrar_id_eq, Registrar.all.map { |x| [x, x.id] }, { include_blank: true }, class: 'form-control selectize' %> <%= f.select :registrar_id_eq, Registrar.all.map { |x| [x, x.id] }, { include_blank: true }, class: 'form-control selectize' %>
@ -38,7 +38,7 @@
<%= f.search_field :valid_to_gteq, value: params[:q][:valid_to_gteq], class: 'form-control js-datepicker', placeholder: t(:valid_to_from) %> <%= f.search_field :valid_to_gteq, value: params[:q][:valid_to_gteq], class: 'form-control js-datepicker', placeholder: t(:valid_to_from) %>
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-4">
<div class="form-group"> <div class="form-group">
<%= f.label :valid_to_until, for: nil %> <%= f.label :valid_to_until, for: nil %>
<%= f.search_field :valid_to_lteq, value: params[:q][:valid_to_lteq], class: 'form-control js-datepicker', placeholder: t(:valid_to_until) %> <%= f.search_field :valid_to_lteq, value: params[:q][:valid_to_lteq], class: 'form-control js-datepicker', placeholder: t(:valid_to_until) %>
@ -46,7 +46,7 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-5">
<div class="form-group"> <div class="form-group">
<%= label_tag :status, nil, for: nil %> <%= label_tag :status, nil, for: nil %>
<%= select_tag :statuses_contains, options_for_select(DomainStatus::STATUSES, params[:statuses_contains]), { multiple: true, class: 'form-control js-combobox' } %> <%= select_tag :statuses_contains, options_for_select(DomainStatus::STATUSES, params[:statuses_contains]), { multiple: true, class: 'form-control js-combobox' } %>
@ -58,13 +58,17 @@
<%= text_field_tag :results_per_page, params[:results_per_page], class: 'form-control', placeholder: t(:results_per_page) %> <%= text_field_tag :results_per_page, params[:results_per_page], class: 'form-control', placeholder: t(:results_per_page) %>
</div> </div>
</div> </div>
<div class="col-md-3 actions"> <div class="col-md-4 actions">
<button class="btn btn-primary"> <button class="btn btn-primary">
&nbsp; &nbsp;
<span class="glyphicon glyphicon-search"></span> <span class="glyphicon glyphicon-search"></span>
&nbsp; &nbsp;
</button> </button>
<%= link_to t('.download_csv_btn'), admin_domains_path(format: :csv, params: params.permit!),
"data-toggle" => "tooltip", "data-placement" => "bottom", "title" => t('.download_csv_btn'),
class: 'btn btn-default' %>
<%= link_to t('.reset_btn'), admin_domains_path, class: 'btn btn-default' %> <%= link_to t('.reset_btn'), admin_domains_path, class: 'btn btn-default' %>
</div> </div>
</div> </div>
<% end %> <% end %>

View file

@ -1,6 +1,6 @@
- content_for :actions do - content_for :actions do
= link_to(t(:back), :back, class: 'btn btn-primary') = link_to(t(:back), :back, class: 'btn btn-primary')
= render 'shared/title', name: t(:repp_log) = render 'shared/title', name: t('.title')
.row .row
.col-md-12 .col-md-12

View file

@ -15,12 +15,22 @@ xml.epp_head do
end if @object end if @object
end end
if @notification.action&.contact if @notification.action&.contact || @notification.registry_lock?
render(partial: 'epp/poll/action', if @notification.registry_lock?
locals: { state = @notification.text.include?('unlocked') ? 'unlock' : 'lock'
builder: xml, xml.extension do
action: @notification.action xml.tag!('changePoll:changeData',
}) 'xmlns:changePoll': 'https://epp.tld.ee/schema/changePoll-1.0.xsd') do
xml.tag!('changePoll:operation', state)
end
end
else
render(partial: 'epp/poll/action',
locals: {
builder: xml,
action: @notification.action,
})
end
end end
render('epp/shared/trID', builder: xml) render('epp/shared/trID', builder: xml)

View file

@ -0,0 +1,65 @@
<%= form_tag registrar_admin_contacts_path, method: :patch, class: 'form-horizontal' do %>
<% if @error %>
<div class="alert alert-danger">
<%= @error %>
</div>
<% end %>
<div class="form-group">
<div class="row">
<div class="col-md-6 control-label">
<p><%= t '.comment' %></p>
</div>
</div>
<div class="col-md-2 control-label">
<%= label_tag :current_contact_id, t('.current_contact_id') %>
</div>
<div class="col-md-4 current_admin_contact">
<%= text_field_tag :current_contact_id, params[:current_contact_id],
list: :contacts,
required: true,
autofocus: true,
class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="col-md-2 control-label">
<%= label_tag :new_contact_id, t('.new_contact_id') %>
</div>
<div class="col-md-4 new_admin_contact">
<%= text_field_tag :new_contact_id, params[:new_contact_id],
list: :contacts,
required: true,
class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="col-md-4 col-md-offset-2 text-right">
<button class="btn btn-warning">
<%= t '.submit_btn' %>
</button>
</div>
</div>
<div class="form-group">
<div class="col-md-6">
<a class="btn btn-default btn-xs" role="button" data-toggle="collapse"
href="#bulk_change_tech_contact_help"><%= t '.help_btn' %></a>
<div class="collapse" id="bulk_change_tech_contact_help">
<div class="well">
<%= t '.help' %>
</div>
</div>
</div>
</div>
<% end %>
<datalist id="contacts">
<% available_contacts.each do |data| %>
<option value="<%= data.second %>"><%= data.first %></option>
<% end %>
</datalist>

View file

@ -10,7 +10,7 @@
<%= label_tag :current_contact_id, t('.current_contact_id') %> <%= label_tag :current_contact_id, t('.current_contact_id') %>
</div> </div>
<div class="col-md-4"> <div class="col-md-4 current_tech_contact">
<%= text_field_tag :current_contact_id, params[:current_contact_id], <%= text_field_tag :current_contact_id, params[:current_contact_id],
list: :contacts, list: :contacts,
required: true, required: true,
@ -24,7 +24,7 @@
<%= label_tag :new_contact_id, t('.new_contact_id') %> <%= label_tag :new_contact_id, t('.new_contact_id') %>
</div> </div>
<div class="col-md-4"> <div class="col-md-4 new_tech_contact">
<%= text_field_tag :new_contact_id, params[:new_contact_id], <%= text_field_tag :new_contact_id, params[:new_contact_id],
list: :contacts, list: :contacts,
required: true, required: true,

View file

@ -12,6 +12,10 @@
<a href="#technical_contact" data-toggle="tab"><%= t '.technical_contact' %></a> <a href="#technical_contact" data-toggle="tab"><%= t '.technical_contact' %></a>
</li> </li>
<li class="<%= 'active' if active_tab == :admin_contact %>">
<a href="#admin_contact" data-toggle="tab"><%= t '.admin_contact' %></a>
</li>
<li class="<%= 'active' if active_tab == :nameserver %>"> <li class="<%= 'active' if active_tab == :nameserver %>">
<a href="#nameserver" data-toggle="tab"><%= t '.nameserver' %></a> <a href="#nameserver" data-toggle="tab"><%= t '.nameserver' %></a>
</li> </li>
@ -31,6 +35,11 @@
<%= render 'tech_contact_form', available_contacts: available_contacts %> <%= render 'tech_contact_form', available_contacts: available_contacts %>
</div> </div>
<div class="tab-pane<%= ' active' if active_tab == :admin_contact %>"
id="admin_contact">
<%= render 'admin_contact_form', available_contacts: available_contacts %>
</div>
<div class="tab-pane<%= ' active' if active_tab == :nameserver %>" id="nameserver"> <div class="tab-pane<%= ' active' if active_tab == :nameserver %>" id="nameserver">
<%= render 'nameserver_form' %> <%= render 'nameserver_form' %>
</div> </div>

View file

@ -36,8 +36,10 @@ module DomainNameRegistry
# Autoload all model subdirs # Autoload all model subdirs
config.autoload_paths += Dir[Rails.root.join('app', 'models', '**/')] config.autoload_paths += Dir[Rails.root.join('app', 'models', '**/')]
config.autoload_paths += Dir[Rails.root.join('app', 'lib', '**/')]
config.autoload_paths += Dir[Rails.root.join('app', 'interactions', '**/')] config.autoload_paths += Dir[Rails.root.join('app', 'interactions', '**/')]
config.eager_load_paths << config.root.join('lib', 'validators') config.eager_load_paths << config.root.join('lib', 'validators')
config.eager_load_paths << config.root.join('app', 'lib')
config.watchable_dirs['lib'] = %i[rb] config.watchable_dirs['lib'] = %i[rb]
config.active_record.schema_format = :sql config.active_record.schema_format = :sql

View file

@ -87,8 +87,11 @@ sk_digi_doc_service_name: 'Testimine'
registrant_api_base_url: registrant_api_base_url:
registrant_api_auth_allowed_ips: '127.0.0.1, 0.0.0.0' #ips, separated with commas registrant_api_auth_allowed_ips: '127.0.0.1, 0.0.0.0' #ips, separated with commas
# Bounces API # Shared key for REST-WHOIS Bounces API incl. CERT
api_shared_key: testkey rwhois_bounces_api_shared_key: testkey
# Link to REST-WHOIS API
rwhois_internal_api_shared_key: testkey
# Base URL (inc. https://) of REST registrant portal # Base URL (inc. https://) of REST registrant portal
# Leave blank to use internal registrant portal # Leave blank to use internal registrant portal

View file

@ -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'])
)

View file

@ -1,9 +1,9 @@
Rails.application.configure do Rails.application.configure do
config.filter_parameters += [:password, /^frame$/, /^nokogiri_frame$/, /^parsed_frame$/] config.filter_parameters += [:password, /^frame$/, /^nokogiri_frame$/, /^parsed_frame$/]
config.filter_parameters << lambda do |key, value| config.filter_parameters << lambda do |key, value|
if key == 'raw_frame' if key == 'raw_frame' && value.respond_to?(:gsub!)
value.to_s.gsub!(/pw>.+<\//, 'pw>[FILTERED]</') value.gsub!(/pw>.+<\//, 'pw>[FILTERED]</')
value.to_s.gsub!(/<eis:legalDocument([^>]+)>([^<])+<\/eis:legalDocument>/, value.gsub!(/<eis:legalDocument([^>]+)>([^<])+<\/eis:legalDocument>/,
"<eis:legalDocument>[FILTERED]</eis:legalDocument>") "<eis:legalDocument>[FILTERED]</eis:legalDocument>")
end end
end end

View file

@ -11,6 +11,7 @@ en:
search_form: search_form:
reset_btn: Reset reset_btn: Reset
download_csv_btn: CSV
form: form:
pending_delete: &pending_delete pending_delete: &pending_delete

View file

@ -4,3 +4,6 @@ en:
index: index:
title: REPP log title: REPP log
reset_btn: Reset reset_btn: Reset
show:
title: REPP log

View file

@ -6,3 +6,5 @@ en:
It was associated with registrant %{old_registrant_code} It was associated with registrant %{old_registrant_code}
and contacts %{old_contacts_codes}. and contacts %{old_contacts_codes}.
contact_update: Contact %{contact} has been updated by registrant contact_update: Contact %{contact} has been updated by registrant
registrar_locked: Domain %{domain_name} has been locked by registrant
registrar_unlocked: Domain %{domain_name} has been unlocked by registrant

View file

@ -0,0 +1,6 @@
en:
registrar:
admin_contacts:
update:
replaced: Admin contacts have been successfully replaced.
replaced: Technical contacts have been successfully replaced.

View file

@ -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.

View file

@ -4,6 +4,7 @@ en:
new: new:
header: Bulk change header: Bulk change
technical_contact: Technical contact technical_contact: Technical contact
admin_contact: Admin contact
nameserver: Nameserver nameserver: Nameserver
bulk_transfer: Bulk transfer bulk_transfer: Bulk transfer
bulk_renew: Bulk renew bulk_renew: Bulk renew
@ -17,6 +18,19 @@ en:
Replace technical contact specified in "current contact ID" with the one in "new Replace technical contact specified in "current contact ID" with the one in "new
contact ID" on any domain registered under this registrar 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
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: nameserver_form:
ip_hint: One IP per line ip_hint: One IP per line
replace_btn: Replace nameserver replace_btn: Replace nameserver
@ -38,3 +52,5 @@ en:
domain_ids: Domains for bulk renewal domain_ids: Domains for bulk renewal
current_balance: Current balance current_balance: Current balance
period: Period period: Period
affected_domains: Affected domains
skipped_domains: Skipped domains

View file

@ -5,3 +5,7 @@ en:
replaced: Technical contacts have been successfully replaced. replaced: Technical contacts have been successfully replaced.
affected_domains: Affected domains affected_domains: Affected domains
skipped_domains: Skipped domains skipped_domains: Skipped domains
process_request:
affected_domains: Affected domains
skipped_domains: Skipped domains
replaced: Technical contacts have been successfully replaced.

View file

@ -64,6 +64,7 @@ Rails.application.routes.draw do
get ':id/transfer_info', to: 'domains#transfer_info', constraints: { id: /.*/ } get ':id/transfer_info', to: 'domains#transfer_info', constraints: { id: /.*/ }
post 'transfer', to: 'domains#transfer' post 'transfer', to: 'domains#transfer'
patch 'contacts', to: 'domains/contacts#update' patch 'contacts', to: 'domains/contacts#update'
patch 'admin_contacts', to: 'domains/admin_contacts#update'
post 'renew/bulk', to: 'domains/renews#bulk_renew' post 'renew/bulk', to: 'domains/renews#bulk_renew'
end end
end end
@ -91,6 +92,7 @@ Rails.application.routes.draw do
end end
resources :auctions, only: %i[index show update], param: :uuid resources :auctions, only: %i[index show update], param: :uuid
resources :contact_requests, only: %i[create update], param: :id
resources :bounces, only: %i[create] resources :bounces, only: %i[create]
end end
@ -136,6 +138,7 @@ Rails.application.routes.draw do
resource :bulk_change, controller: :bulk_change, only: :new resource :bulk_change, controller: :bulk_change, only: :new
post '/bulk_renew/new', to: 'bulk_change#bulk_renew', as: :bulk_renew post '/bulk_renew/new', to: 'bulk_change#bulk_renew', as: :bulk_renew
resource :tech_contacts, only: :update resource :tech_contacts, only: :update
resource :admin_contacts, only: :update
resource :nameservers, only: :update resource :nameservers, only: :update
resources :contacts, constraints: {:id => /[^\/]+(?=#{ ActionController::Renderers::RENDERERS.map{|e| "\\.#{e}\\z"}.join("|") })|[^\/]+/} do resources :contacts, constraints: {:id => /[^\/]+(?=#{ ActionController::Renderers::RENDERERS.map{|e| "\\.#{e}\\z"}.join("|") })|[^\/]+/} do
member do member do

View file

@ -0,0 +1,30 @@
# Admin domain contacts
## PATCH https://repp.internet.ee/v1/domains/admin_contacts
Replaces admin domain contacts of the current registrar.
### Example request
```
PATCH /repp/v1/domains/admin_contacts HTTP/1.1
Accept: application/json
Content-Type: application/json
Authorization: Basic dGVzdDp0ZXN0dGVzdA==
{
"current_contact_id": "ATSAA:749AA80F",
"new_contact_id": "ATSAA:E36957D7"
}
```
### Example response
```
{
"code": 1000,
"message": "Command completed successfully",
"data": {
"affected_domains": [
"private.ee",
],
"skipped_domains": []
}
}
```

View file

@ -1,7 +1,7 @@
# Domain contacts # Tech domain contacts
## PATCH https://repp.internet.ee/v1/domains/contacts ## PATCH https://repp.internet.ee/v1/domains/contacts
Replaces all domain contacts of the current registrar. Replaces technical domain contacts of the current registrar.
### Example request ### Example request
``` ```

View file

@ -35,7 +35,6 @@ class JavaScriptApplicationSystemTestCase < ApplicationSystemTestCase
def setup def setup
DatabaseCleaner.start DatabaseCleaner.start
super super
Capybara.current_driver = :chrome Capybara.current_driver = :chrome

8
test/fixtures/contact_requests.yml vendored Normal file
View file

@ -0,0 +1,8 @@
new:
whois_record_id: 1
email: aaa@bbb.com
name: Testname
status: new
secret: somesecret
valid_to: 2010-07-05

View file

@ -0,0 +1,39 @@
require 'test_helper'
require 'application_system_test_case'
class AdminAreaAccountActivitiesIntegrationTest < ApplicationSystemTestCase
# /admin/account_activities
setup do
sign_in users(:admin)
@original_default_language = Setting.default_language
end
def test_show_account_activities_page
account_activities(:one).update(sum: "123.00")
visit admin_account_activities_path
assert_text 'Account activities'
end
def test_default_url_params
account_activities(:one).update(sum: "123.00")
visit admin_root_path
click_link_or_button 'Settings', match: :first
find(:xpath, "//ul/li/a[text()='Account activities']").click
assert has_current_path?(admin_account_activities_path(created_after: 'today'))
end
def test_download_account_activity
now = Time.zone.parse('2010-07-05 08:00')
travel_to now
account_activities(:one).update(sum: "123.00")
get admin_account_activities_path(format: :csv)
assert_response :ok
assert_equal "text/csv", response.headers['Content-Type']
assert_equal %(attachment; filename="account_activities_#{Time.zone.now.to_formatted_s(:number)}.csv"; filename*=UTF-8''account_activities_#{Time.zone.now.to_formatted_s(:number)}.csv),
response.headers['Content-Disposition']
assert_not_empty response.body
end
end

View file

@ -0,0 +1,101 @@
require 'test_helper'
require 'application_system_test_case'
class AdminAreaAdminUsersIntegrationTest < JavaScriptApplicationSystemTestCase
include Devise::Test::IntegrationHelpers
include ActionView::Helpers::NumberHelper
setup do
WebMock.allow_net_connect!
@original_default_language = Setting.default_language
sign_in users(:admin)
end
def test_create_new_admin_user
createNewAdminUser(true)
end
def test_create_with_invalid_data_new_admin_user
createNewAdminUser(false)
end
def test_edit_successfully_exist_record
createNewAdminUser(true)
visit admin_admin_users_path
click_on 'test_user_name'
assert_text 'General'
click_on 'Edit'
fill_in 'Password', with: 'test_password'
fill_in 'Password confirmation', with: 'test_password'
click_on 'Save'
assert_text 'Record updated'
end
def test_edit_exist_record_with_invalid_data
createNewAdminUser(true)
visit admin_admin_users_path
click_on 'test_user_name'
assert_text 'General'
click_on 'Edit'
fill_in 'Password', with: 'test_password'
fill_in 'Password confirmation', with: 'test_password2'
click_on 'Save'
assert_text 'Failed to update record'
end
def test_delete_exist_record
createNewAdminUser(true)
visit admin_admin_users_path
click_on 'test_user_name'
assert_text 'General'
click_on 'Delete'
page.driver.browser.switch_to.alert.accept
assert_text 'Record deleted'
end
private
def createNewAdminUser(valid)
visit admin_admin_users_path
click_on 'New admin user'
fill_in 'Username', with: 'test_user_name'
# If valid=true creating valid user, if else, then with invalid data
if valid
fill_in 'Password', with: 'test_password'
fill_in 'Password confirmation', with: 'test_password'
else
fill_in 'Password', with: 'test_password'
fill_in 'Password confirmation', with: 'test_password2'
end
fill_in 'Identity code', with: '38903110313'
fill_in 'Email', with: 'oleg@tester.ee'
select 'Estonia', from: 'admin_user_country_code', match: :first
select_element = find(:xpath, "/html/body/div[2]/form/div[2]/div/div[7]/div[2]/div/div[1]")
select_element.click
option_element = find(:xpath, "/html/body/div[2]/form/div[2]/div/div[7]/div[2]/div/div[2]/div/div[1]")
option_element.click
click_on 'Save'
if valid
assert_text 'Record created'
else
assert_text 'Failed to create record'
end
end
end

View file

@ -0,0 +1,68 @@
require 'test_helper'
require 'application_system_test_case'
# /admin/blocked_domains
class AdminAreaBlockedDomainsIntegrationTest < JavaScriptApplicationSystemTestCase
setup do
WebMock.allow_net_connect!
sign_in users(:admin)
@domain = domains(:shop)
@blocked_domain = blocked_domains(:one)
end
def test_page_successfully_loaded
visit_admin_blocked_domains_path
end
def test_add_into_blocked_list
visit_admin_blocked_domains_path
add_domain_into_blocked_list(true)
end
def test_add_into_blocked_list_same_domain
visit_admin_blocked_domains_path
add_domain_into_blocked_list(true)
add_domain_into_blocked_list(false)
end
def test_delete_domain_from_blocked_list
visit_admin_blocked_domains_path
add_domain_into_blocked_list(true)
click_link_or_button 'Delete', match: :first
# Accept to delete in modal window
page.driver.browser.switch_to.alert.accept
assert_text 'Domain deleted!'
end
def test_find_blocked_domain_from_blocked_list
visit_admin_blocked_domains_path
add_domain_into_blocked_list(true)
fill_in 'Name', with: @domain.name
find(:xpath, "//span[@class='glyphicon glyphicon-search']").click
assert_text @domain.name
end
private
def visit_admin_blocked_domains_path
visit admin_blocked_domains_path
assert_text 'Blocked domains'
end
def add_domain_into_blocked_list(value)
click_on 'New blocked domain'
assert_text 'Add domain to blocked list'
fill_in 'Name', with: @domain.name
click_on 'Save'
return assert_text 'Domain added!' if value
return assert_text 'Failed to add domain!'
end
end

View file

@ -0,0 +1,71 @@
require 'test_helper'
require 'application_system_test_case'
class AdminAreaCertificatesIntegrationTest < JavaScriptApplicationSystemTestCase
setup do
WebMock.allow_net_connect!
sign_in users(:admin)
@apiuser = users(:api_bestnames)
@certificate = certificates(:api)
@certificate.update!(csr: "-----BEGIN CERTIFICATE REQUEST-----\nMIICszCCAZsCAQAwbjELMAkGA1UEBhMCRUUxFDASBgNVBAMMC2ZyZXNoYm94LmVl\nMRAwDgYDVQQHDAdUYWxsaW5uMREwDwYDVQQKDAhGcmVzaGJveDERMA8GA1UECAwI\nSGFyanVtYWExETAPBgNVBAsMCEZyZXNoYm94MIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEA1VVESynZoZhIbe8s9zHkELZ/ZDCGiM2Q8IIGb1IOieT5U2mx\nIsVXz85USYsSQY9+4YdEXnupq9fShArT8pstS/VN6BnxdfAiYXc3UWWAuaYAdNGJ\nDr5Jf6uMt1wVnCgoDL7eJq9tWMwARC/viT81o92fgqHFHW0wEolfCmnpik9o0ACD\nFiWZ9IBIevmFqXtq25v9CY2cT9+eZW127WtJmOY/PKJhzh0QaEYHqXTHWOLZWpnp\nHH4elyJ2CrFulOZbHPkPNB9Nf4XQjzk1ffoH6e5IVys2VV5xwcTkF0jY5XTROVxX\nlR2FWqic8Q2pIhSks48+J6o1GtXGnTxv94lSDwIDAQABoAAwDQYJKoZIhvcNAQEL\nBQADggEBAEFcYmQvcAC8773eRTWBJJNoA4kRgoXDMYiiEHih5iJPVSxfidRwYDTF\nsP+ttNTUg3JocFHY75kuM9T2USh+gu/trRF0o4WWa+AbK3JbbdjdT1xOMn7XtfUU\nZ/f1XCS9YdHQFCA6nk4Z+TLWwYsgk7n490AQOiB213fa1UIe83qIfw/3GRqRUZ7U\nwIWEGsHED5WT69GyxjyKHcqGoV7uFnqFN0sQVKVTy/NFRVQvtBUspCbsOirdDRie\nAB2KbGHL+t1QrRF10szwCJDyk5aYlVhxvdI8zn010nrxHkiyQpDFFldDMLJl10BW\n2w9PGO061z+tntdRcKQGuEpnIr9U5Vs=\n-----END CERTIFICATE REQUEST-----\n")
end
def test_show_certificate_info
show_certificate_info
end
def test_destroy_certificate
show_certificate_info
find(:xpath, "//a[text()='Delete']").click
page.driver.browser.switch_to.alert.accept
assert_text 'Record deleted'
end
def test_download_csr
get download_csr_admin_api_user_certificate_path(api_user_id: @apiuser.id, id: @certificate.id)
assert_response :ok
assert_equal 'application/octet-stream', response.headers['Content-Type']
assert_equal "attachment; filename=\"test_bestnames.csr.pem\"; filename*=UTF-8''test_bestnames.csr.pem", response.headers['Content-Disposition']
assert_not_empty response.body
end
def test_download_crt
get download_crt_admin_api_user_certificate_path(api_user_id: @apiuser.id, id: @certificate.id)
assert_response :ok
assert_equal 'application/octet-stream', response.headers['Content-Type']
assert_equal "attachment; filename=\"test_bestnames.crt.pem\"; filename*=UTF-8''test_bestnames.crt.pem", response.headers['Content-Disposition']
assert_not_empty response.body
end
def test_failed_to_revoke_certificate
show_certificate_info
find(:xpath, "//a[text()='Revoke this certificate']").click
assert_text 'Failed to update record'
end
def test_new_api_user
visit new_admin_registrar_api_user_path(registrar_id: registrars(:bestnames).id)
fill_in 'Username', with: 'testapiuser'
fill_in 'Password', with: 'secretpassword'
fill_in 'Identity code', with: '60305062718'
click_on 'Create API user'
assert_text 'API user has been successfully created'
end
private
def show_certificate_info
visit admin_api_user_certificate_path(api_user_id: @apiuser.id, id: @certificate.id)
assert_text 'Certificates'
end
end

View file

@ -0,0 +1,52 @@
# admin_epp_logs_path
require 'test_helper'
require 'application_system_test_case'
class AdminEppLogsIntegrationTest < ApplicationSystemTestCase
setup do
sign_in users(:admin)
end
def test_visit_epp_logs_page
visit admin_epp_logs_path
assert_text 'EPP log'
end
def test_show_epp_log_page
visit admin_epp_logs_path
send_epp_request_hello
visit admin_epp_logs_path
find(:xpath, "//tbody/tr/td/a", match: :first).click
assert_text 'Details'
end
def test_dates_sort
Capybara.exact = true
visit admin_epp_logs_path
send_epp_request_hello
visit admin_epp_logs_path
find(:xpath, "//a[contains(text(), 'Created at')]", match: :first).click
find(:xpath, "//a[contains(text(), 'Created at')]", match: :first).click
epp_log_date = find(:xpath, "//table/tbody/tr/td[6]", match: :first).text(:all)
date_now = Date.today.to_s(:db)
assert_match /#{date_now}/, epp_log_date
end
private
def send_epp_request_hello
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<hello/>
</epp>
XML
get epp_hello_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=non-existent' }
end
end

View file

@ -6,6 +6,27 @@ class AdminAreaInvoicesIntegrationTest < ApplicationIntegrationTest
sign_in users(:admin) sign_in users(:admin)
end end
def test_create_new_invoice
visit new_admin_invoice_path
assert_text 'Create new invoice'
select 'Best Names', from: 'deposit_registrar_id', match: :first
fill_in 'Amount', with: '1000'
click_on 'Save'
assert_equal page.status_code, 200
end
def test_visit_list_of_invoices_pages
visit admin_invoices_path
assert_text 'Invoices'
end
def test_visit_invoice_page
visit admin_invoices_path(id: @invoice.id)
assert_text "Invoice no. #{@invoice.number}"
end
def test_downloads_invoice def test_downloads_invoice
assert_equal 1, @invoice.number assert_equal 1, @invoice.number

View file

@ -0,0 +1,60 @@
require 'test_helper'
require 'application_system_test_case'
class AdminAreaPendingDeleteIntegrationTest < JavaScriptApplicationSystemTestCase
setup do
WebMock.allow_net_connect!
sign_in users(:admin)
@domain = domains(:shop)
@token = '123456'
@domain.update!(statuses: [DomainStatus::PENDING_DELETE_CONFIRMATION],
registrant_verification_asked_at: Time.zone.now - 1.day,
registrant_verification_token: @token)
end
def test_accept_pending_delete
visit edit_admin_domain_path(id: @domain.id)
click_on 'Accept'
page.driver.browser.switch_to.alert.accept
assert_text 'Pending was successfully applied.'
end
def test_accept_pending_delete_no_success
@domain.update!(statuses: [DomainStatus::PENDING_DELETE_CONFIRMATION],
registrant_verification_asked_at: Time.zone.now - 1.day,
registrant_verification_token: nil)
visit edit_admin_domain_path(id: @domain.id)
click_on 'Accept'
page.driver.browser.switch_to.alert.accept
assert_text 'Not success'
end
def test_reject_panding_delete
visit edit_admin_domain_path(id: @domain.id)
click_on 'Reject'
page.driver.browser.switch_to.alert.accept
assert_text 'Pending was successfully removed.'
end
def test_accept_pending_delete_no_success
@domain.update!(statuses: [DomainStatus::PENDING_DELETE_CONFIRMATION],
registrant_verification_asked_at: Time.zone.now - 1.day,
registrant_verification_token: nil)
visit edit_admin_domain_path(id: @domain.id)
click_on 'Reject'
page.driver.browser.switch_to.alert.accept
assert_text 'Not success'
end
end

View file

@ -0,0 +1,96 @@
require 'test_helper'
require 'application_system_test_case'
class AdminAreaPendingUpdateIntegrationTest < JavaScriptApplicationSystemTestCase
setup do
WebMock.allow_net_connect!
sign_in users(:admin)
@domain = domains(:hospital)
@new_registrant = contacts(:jack)
@user = users(:api_bestnames)
@token = '123456'
@domain.update!(statuses: [DomainStatus::PENDING_UPDATE],
registrant_verification_asked_at: Time.zone.now - 1.day,
registrant_verification_token: @token)
end
def test_accept_pending_update
pending_json = { new_registrant_id: @new_registrant.id,
new_registrant_name: @new_registrant.name,
new_registrant_email: @new_registrant.email,
current_user_id: @user.id }
@domain.update(pending_json: pending_json)
@domain.reload
visit edit_admin_domain_path(id: @domain.id)
click_on 'Accept'
page.driver.browser.switch_to.alert.accept
assert_text 'Pending was successfully applied.'
end
def test_accept_pending_update_no_success
@domain.update!(statuses: [DomainStatus::PENDING_UPDATE],
registrant_verification_asked_at: Time.zone.now - 1.day,
registrant_verification_token: nil)
pending_json = { new_registrant_id: @new_registrant.id,
new_registrant_name: @new_registrant.name,
new_registrant_email: @new_registrant.email,
current_user_id: @user.id,
}
@domain.update(pending_json: pending_json)
@domain.reload
visit edit_admin_domain_path(id: @domain.id)
click_on 'Accept'
page.driver.browser.switch_to.alert.accept
assert_text 'Not success'
end
def test_reject_panding_update
pending_json = { new_registrant_id: @new_registrant.id,
new_registrant_name: @new_registrant.name,
new_registrant_email: @new_registrant.email,
current_user_id: @user.id,
}
@domain.update(pending_json: pending_json)
@domain.reload
visit edit_admin_domain_path(id: @domain.id)
click_on 'Reject'
page.driver.browser.switch_to.alert.accept
assert_text 'Pending was successfully removed.'
end
def test_accept_pending_update_no_success
@domain.update!(statuses: [DomainStatus::PENDING_UPDATE],
registrant_verification_asked_at: Time.zone.now - 1.day,
registrant_verification_token: nil)
pending_json = { new_registrant_id: @new_registrant.id,
new_registrant_name: @new_registrant.name,
new_registrant_email: @new_registrant.email,
current_user_id: @user.id,
}
@domain.update(pending_json: pending_json)
@domain.reload
visit edit_admin_domain_path(id: @domain.id)
click_on 'Reject'
page.driver.browser.switch_to.alert.accept
assert_text 'Not success'
end
end

View file

@ -0,0 +1,23 @@
require 'test_helper'
require 'application_system_test_case'
class AdminAreaReppLogsIntegrationTest < ApplicationSystemTestCase
setup do
sign_in users(:admin)
end
def test_repp_logs_page
visit admin_repp_logs_path
assert_text 'REPP log'
end
def test_show_repp_log_page
visit admin_repp_logs_path
get repp_v1_contacts_path
visit admin_repp_logs_path
find(:xpath, "//tbody/tr/td/a", match: :first).click
assert_text 'REPP log'
end
end

View file

@ -0,0 +1,39 @@
require 'test_helper'
require 'application_system_test_case'
class AdminAreaReservedDomainsIntegrationTest < JavaScriptApplicationSystemTestCase
setup do
WebMock.allow_net_connect!
@original_default_language = Setting.default_language
sign_in users(:admin)
@reserved_domain = reserved_domains(:one)
end
def test_remove_reserved_domain
visit admin_reserved_domains_path
click_link_or_button 'Delete', match: :first
page.driver.browser.switch_to.alert.accept
assert_text 'Domain deleted!'
end
def test_add_invalid_domain
visit admin_reserved_domains_path
click_on 'New reserved domain'
fill_in "Name", with: "@##@$"
click_on 'Save'
assert_text 'Failed to add domain!'
end
def test_update_reserved_domain
visit admin_reserved_domains_path
click_link_or_button 'Edit Pw', match: :first
fill_in 'Password', with: '12345678'
click_on 'Save'
assert_text 'Domain updated!'
end
end

View file

@ -0,0 +1,94 @@
require 'test_helper'
require 'application_system_test_case'
class AdminAreaWhiteIpsIntegrationTest < JavaScriptApplicationSystemTestCase
setup do
WebMock.allow_net_connect!
sign_in users(:admin)
@registrar = registrars(:bestnames)
@white_ip = white_ips(:one)
end
def test_visit_new_whitelisted_ip_page
visit_new_whitelisted_ip_page
end
def test_create_new_whitelisted_ip
visit_new_whitelisted_ip_page
fill_in 'IPv4', with: "127.0.0.1"
fill_in 'IPv6', with: "::ffff:192.0.2.1"
find(:css, "#white_ip_interfaces_api").set(true)
find(:css, "#white_ip_interfaces_registrar").set(true)
click_on 'Save'
assert_text 'Record created'
end
def test_failed_to_create_new_whitelisted_ip
visit_new_whitelisted_ip_page
fill_in 'IPv4', with: "asdadadad.asd"
click_on 'Save'
assert_text 'Failed to create record'
end
def test_visit_edit_whitelisted_ip_page
visit_edit_whitelisted_ip_page
end
def test_update_whitelisted_ip
visit_info_whitelisted_ip_page
click_on 'Edit'
fill_in 'IPv4', with: "127.0.0.2"
find(:css, "#white_ip_interfaces_api").set(false)
click_on 'Save'
assert_text 'Record updated'
end
def test_failed_to_update_whitelisted_ip
visit_info_whitelisted_ip_page
click_on 'Edit'
fill_in 'IPv4', with: "asdadad#"
click_on 'Save'
assert_text 'Failed to update record'
end
def test_visit_info_whitelisted_ip_page
visit_info_whitelisted_ip_page
end
def test_delete_whitelisted_ip
visit_info_whitelisted_ip_page
click_on 'Delete'
page.driver.browser.switch_to.alert.accept
assert_text 'Record deleted'
end
private
def visit_new_whitelisted_ip_page
visit new_admin_registrar_white_ip_path(registrar_id: @registrar.id)
assert_text 'New whitelisted IP'
end
def visit_edit_whitelisted_ip_page
visit edit_admin_registrar_white_ip_path(registrar_id: @registrar.id, id: @white_ip.id)
assert_text 'Edit white IP'
end
def visit_info_whitelisted_ip_page
visit admin_registrar_white_ip_path(registrar_id: @registrar.id, id: @white_ip.id)
assert_text 'White IP'
end
end

View file

@ -0,0 +1,153 @@
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,
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.code,
new_contact_id: @admin_new.code },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert_response :bad_request
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
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 }
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.code,
new_contact_id: @admin_new.code },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert domains(:airport).admin_contacts.find_by(code: @admin_current.code)
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 }
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: @admin_current.code,
new_contact_id: @admin_new.code },
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: @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.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.code,
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: @admin_new.code},
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: @admin_current.code,
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: @admin_current.code,
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_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: @admin_current.code,
new_contact_id: @admin_new.code },
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
ActionController::HttpAuthentication::Basic.encode_credentials('test_bestnames', 'testtest')
end
end

View file

@ -107,6 +107,24 @@ class APIDomainContactsTest < ApplicationIntegrationTest
JSON.parse(response.body, symbolize_names: true) JSON.parse(response.body, symbolize_names: true)
end 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 private
def http_auth_key def http_auth_key

View file

@ -2,7 +2,7 @@ require 'test_helper'
class BouncesApiV1CreateTest < ActionDispatch::IntegrationTest class BouncesApiV1CreateTest < ActionDispatch::IntegrationTest
def setup def setup
@api_key = "Basic #{ENV['api_shared_key']}" @api_key = "Basic #{ENV['rwhois_bounces_api_shared_key']}"
@headers = { "Authorization": "#{@api_key}" } @headers = { "Authorization": "#{@api_key}" }
@json_body = { "data": valid_bounce_request }.as_json @json_body = { "data": valid_bounce_request }.as_json
end end

View file

@ -0,0 +1,68 @@
require 'test_helper'
class ApiV1ContactRequestTest < ActionDispatch::IntegrationTest
def setup
@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
@contact_request = contact_requests(:new)
end
def test_authorizes_api_request
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_create, headers: invalid_headers
assert_response :unauthorized
end
def test_saves_new_contact_request
request_body = @json_create.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 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

View file

@ -1,5 +1,6 @@
require 'test_helper' require 'test_helper'
require 'auth_token/auth_token_creator' require 'auth_token/auth_token_creator'
require 'json'
CompanyRegisterClientStub = Struct.new(:any_method) do CompanyRegisterClientStub = Struct.new(:any_method) do
def representation_rights(citizen_personal_code:, citizen_country_code:) def representation_rights(citizen_personal_code:, citizen_country_code:)
@ -55,6 +56,42 @@ class RegistrantApiV1ContactListTest < ActionDispatch::IntegrationTest
assert_equal '1234', response_json.first[:ident][:code] assert_equal '1234', response_json.first[:ident][:code]
end end
def test_out_of_range_limit
get api_v1_registrant_contacts_path + "?limit=300", as: :json, headers: { 'HTTP_AUTHORIZATION' => auth_token }
response_json = JSON.parse(response.body, symbolize_names: true)
text_response = JSON.pretty_generate(response_json[:errors][0][:limit][0])
assert_equal text_response, '"parameter is out of range"'
end
def test_negative_offset
get api_v1_registrant_contacts_path + "?offset=-300", as: :json, headers: { 'HTTP_AUTHORIZATION' => auth_token }
response_json = JSON.parse(response.body, symbolize_names: true)
text_response = JSON.pretty_generate(response_json[:errors][0][:offset][0])
assert_equal text_response, '"parameter is out of range"'
end
def test_show_valid_contact
get api_v1_registrant_contacts_path + "/eb2f2766-b44c-4e14-9f16-32ab1a7cb957", as: :json, headers: { 'HTTP_AUTHORIZATION' => auth_token }
response_json = JSON.parse(response.body, symbolize_names: true)
text_response = response_json[:name]
assert_equal @contact[:name], text_response
end
def test_show_invalid_contact
get api_v1_registrant_contacts_path + "/435", as: :json, headers: { 'HTTP_AUTHORIZATION' => auth_token }
response_json = JSON.parse(response.body, symbolize_names: true)
text_response = response_json[:errors][0][:base][0]
assert_equal text_response, 'Contact not found'
end
private private
def delete_direct_contact def delete_direct_contact

View file

@ -4,11 +4,12 @@ require 'auth_token/auth_token_creator'
class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest
setup do setup do
@contact = contacts(:john) @contact = contacts(:john)
@contact_org = contacts(:acme_ltd)
@original_address_processing = Setting.address_processing @original_address_processing = Setting.address_processing
@original_fax_enabled_setting = ENV['fax_enabled'] @original_fax_enabled_setting = ENV['fax_enabled']
@user = users(:registrant) @user = users(:registrant)
end end
teardown do teardown do
@ -90,6 +91,32 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest
@contact.address @contact.address
end end
def test_update_address_when_enabled_without_address_params
Setting.address_processing = true
patch api_v1_registrant_contact_path(@contact.uuid), params: { address: { } },
as: :json,
headers: { 'HTTP_AUTHORIZATION' => auth_token }
assert_response :bad_request
@contact.reload
assert_equal Contact::Address.new(nil, nil, nil, nil, nil),
@contact.address
end
def test_update_address_when_enabled_without_address_params
Setting.address_processing = true
patch api_v1_registrant_contact_path(@contact.uuid), params: { },
as: :json,
headers: { 'HTTP_AUTHORIZATION' => auth_token }
assert_response :bad_request
@contact.reload
assert_equal Contact::Address.new(nil, nil, nil, nil, nil),
@contact.address
end
def test_address_is_optional_when_enabled def test_address_is_optional_when_enabled
Setting.address_processing = true Setting.address_processing = true
@contact.update!(street: 'any', zip: 'any', city: 'any', state: 'any', country_code: 'US') @contact.update!(street: 'any', zip: 'any', city: 'any', state: 'any', country_code: 'US')
@ -211,6 +238,21 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest
symbolize_names: true) symbolize_names: true)
end end
def test_org_disclosed_attributes
patch api_v1_registrant_contact_path(@contact_org.uuid), params: { disclosed_attributes: ["some_attr"] },
as: :json,
headers: { 'HTTP_AUTHORIZATION' => auth_token }
assert_response :bad_request
err_msg = "Legal person's data is visible by default and cannot be concealed. Please remove this parameter."
response_json = JSON.parse(response.body, symbolize_names: true)
response_msg = response_json[:errors][0][:disclosed_attributes][0]
assert_equal err_msg, response_msg
end
def test_unmanaged_contact_cannot_be_updated def test_unmanaged_contact_cannot_be_updated
assert_equal 'US-1234', @user.registrant_ident assert_equal 'US-1234', @user.registrant_ident
@contact.update!(ident: '12345') @contact.update!(ident: '12345')

View file

@ -26,7 +26,7 @@ class EppContactCheckBaseTest < EppTestCase
response_xml = Nokogiri::XML(response.body) response_xml = Nokogiri::XML(response.body)
assert_epp_response :completed_successfully assert_epp_response :completed_successfully
assert_equal 'john-001', response_xml.at_xpath('//contact:id', contact: xml_schema).text assert_equal "#{@contact.registrar.code}:JOHN-001".upcase, response_xml.at_xpath('//contact:id', contact: xml_schema).text
end end
def test_contact_is_available def test_contact_is_available
@ -52,7 +52,8 @@ class EppContactCheckBaseTest < EppTestCase
end end
def test_contact_is_unavailable def test_contact_is_unavailable
assert_equal 'john-001', @contact.code @contact.update_columns(code: "#{@contact.registrar.code}:JOHN-001".upcase)
assert @contact.code, "#{@contact.registrar.code}:JOHN-001".upcase
request_xml = <<-XML request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
@ -98,6 +99,58 @@ class EppContactCheckBaseTest < EppTestCase
assert_equal 3, response_xml.xpath('//contact:cd', contact: xml_schema).size assert_equal 3, response_xml.xpath('//contact:cd', contact: xml_schema).size
end end
def test_check_contact_with_prefix
@contact.update_columns(code: "#{@contact.registrar.code}:JOHN-001".upcase)
assert @contact.code, "#{@contact.registrar.code}:JOHN-001".upcase
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<check>
<contact:check xmlns:contact="https://epp.tld.ee/schema/contact-ee-1.1.xsd">
<contact:id>BESTNAMES:JOHN-001</contact:id>
</contact:check>
</check>
</command>
</epp>
XML
post epp_check_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
response_xml = Nokogiri::XML(response.body)
assert_epp_response :completed_successfully
assert_equal "#{@contact.registrar.code}:JOHN-001".upcase, response_xml.at_xpath('//contact:id', contact: xml_schema).text
assert_equal 'in use', response_xml.at_xpath('//contact:reason', contact: xml_schema).text
end
def test_check_contact_without_prefix
@contact.update_columns(code: "#{@contact.registrar.code}:JOHN-001".upcase)
assert @contact.code, "#{@contact.registrar.code}:JOHN-001".upcase
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<check>
<contact:check xmlns:contact="https://epp.tld.ee/schema/contact-ee-1.1.xsd">
<contact:id>JOHN-001</contact:id>
</contact:check>
</check>
</command>
</epp>
XML
post epp_check_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
response_xml = Nokogiri::XML(response.body)
assert_epp_response :completed_successfully
assert_equal "#{@contact.registrar.code}:JOHN-001".upcase, response_xml.at_xpath('//contact:id', contact: xml_schema).text
assert_equal 'in use', response_xml.at_xpath('//contact:reason', contact: xml_schema).text
end
private private
def xml_schema def xml_schema

View file

@ -44,6 +44,58 @@ class EppContactInfoBaseTest < EppTestCase
contact: xml_schema).text contact: xml_schema).text
end end
def test_get_info_about_contact_with_prefix
@contact.update_columns(code: 'TEST:JOHN-001')
assert @contact.code, 'TEST:JOHN-001'
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<info>
<contact:info xmlns:contact="https://epp.tld.ee/schema/contact-ee-1.1.xsd">
<contact:id>TEST:JOHN-001</contact:id>
</contact:info>
</info>
</command>
</epp>
XML
post epp_info_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
response_xml = Nokogiri::XML(response.body)
assert_epp_response :completed_successfully
assert_equal 'TEST:JOHN-001', response_xml.at_xpath('//contact:id', contact: xml_schema).text
assert_equal '+555.555', response_xml.at_xpath('//contact:voice', contact: xml_schema).text
end
def test_get_info_about_contact_without_prefix
@contact.update_columns(code: "#{@contact.registrar.code}:JOHN-001".upcase)
assert @contact.code, "#{@contact.registrar.code}:JOHN-001".upcase
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<info>
<contact:info xmlns:contact="https://epp.tld.ee/schema/contact-ee-1.1.xsd">
<contact:id>JOHN-001</contact:id>
</contact:info>
</info>
</command>
</epp>
XML
post epp_info_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
response_xml = Nokogiri::XML(response.body)
assert_epp_response :completed_successfully
assert_equal "#{@contact.registrar.code}:JOHN-001".upcase, response_xml.at_xpath('//contact:id', contact: xml_schema).text
assert_equal '+555.555', response_xml.at_xpath('//contact:voice', contact: xml_schema).text
end
def test_hides_password_and_name_when_current_registrar_is_not_sponsoring def test_hides_password_and_name_when_current_registrar_is_not_sponsoring
non_sponsoring_registrar = registrars(:goodnames) non_sponsoring_registrar = registrars(:goodnames)
@contact.update!(registrar: non_sponsoring_registrar) @contact.update!(registrar: non_sponsoring_registrar)

View file

@ -2,6 +2,51 @@ require 'test_helper'
class EppDomainCreateBaseTest < EppTestCase class EppDomainCreateBaseTest < EppTestCase
def test_illegal_chars_in_dns_key
name = "new.#{dns_zones(:one).origin}"
contact = contacts(:john)
registrant = contact.becomes(Registrant)
pub_key = "AwEAAddt2AkLf\n
\n
YGKgiEZB5SmIF8E\n
vrjxNMH6HtxW\rEA4RJ9Ao6LCWheg8"
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<create>
<domain:create xmlns:domain="https://epp.tld.ee/schema/domain-eis-1.0.xsd">
<domain:name>#{name}</domain:name>
<domain:registrant>#{registrant.code}</domain:registrant>
</domain:create>
</create>
<extension>
<secDNS:create xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1">
<secDNS:keyData>
<secDNS:flags>257</secDNS:flags>
<secDNS:protocol>3</secDNS:protocol>
<secDNS:alg>8</secDNS:alg>
<secDNS:pubKey>#{pub_key}</secDNS:pubKey>
</secDNS:keyData>
</secDNS:create>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:legalDocument type="pdf">#{'test' * 2000}</eis:legalDocument>
</eis:extdata>
</extension>
</command>
</epp>
XML
assert_no_difference 'Domain.count' do
post epp_create_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
end
assert_epp_response :parameter_value_syntax_error
end
def test_not_registers_domain_without_legaldoc def test_not_registers_domain_without_legaldoc
now = Time.zone.parse('2010-07-05') now = Time.zone.parse('2010-07-05')
travel_to now travel_to now
@ -31,6 +76,230 @@ class EppDomainCreateBaseTest < EppTestCase
assert_epp_response :required_parameter_missing assert_epp_response :required_parameter_missing
end end
def test_create_domain_with_unique_contact
now = Time.zone.parse('2010-07-05')
travel_to now
name = "new.#{dns_zones(:one).origin}"
contact = contacts(:john)
registrant = contact.becomes(Registrant)
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<create>
<domain:create xmlns:domain="https://epp.tld.ee/schema/domain-eis-1.0.xsd">
<domain:name>#{name}</domain:name>
<domain:registrant>#{registrant.code}</domain:registrant>
<domain:contact type="admin">#{contacts(:jane).code}</domain:contact>
<domain:contact type="tech">#{contacts(:william).code}</domain:contact>
</domain:create>
</create>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:legalDocument type="pdf">#{'test' * 2000}</eis:legalDocument>
</eis:extdata>
</extension>
</command>
</epp>
XML
assert_difference 'Domain.count' do
post epp_create_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
end
assert_epp_response :completed_successfully
end
def test_create_domain_with_array_of_not_unique_admins_and_techs
now = Time.zone.parse('2010-07-05')
travel_to now
name = "new.#{dns_zones(:one).origin}"
contact = contacts(:john)
registrant = contact.becomes(Registrant)
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<create>
<domain:create xmlns:domain="https://epp.tld.ee/schema/domain-eis-1.0.xsd">
<domain:name>#{name}</domain:name>
<domain:registrant>#{registrant.code}</domain:registrant>
<domain:contact type="admin">#{contact.code}</domain:contact>
<domain:contact type="admin">#{contact.code}</domain:contact>
<domain:contact type="tech">#{contact.code}</domain:contact>
<domain:contact type="tech">#{contact.code}</domain:contact>
</domain:create>
</create>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:legalDocument type="pdf">#{'test' * 2000}</eis:legalDocument>
</eis:extdata>
</extension>
</command>
</epp>
XML
assert_no_difference 'Domain.count' do
post epp_create_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
end
assert_epp_response :parameter_value_policy_error
end
def test_create_domain_with_array_of_not_unique_admins
now = Time.zone.parse('2010-07-05')
travel_to now
name = "new.#{dns_zones(:one).origin}"
contact = contacts(:john)
registrant = contact.becomes(Registrant)
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<create>
<domain:create xmlns:domain="https://epp.tld.ee/schema/domain-eis-1.0.xsd">
<domain:name>#{name}</domain:name>
<domain:registrant>#{registrant.code}</domain:registrant>
<domain:contact type="admin">#{contact.code}</domain:contact>
<domain:contact type="admin">#{contact.code}</domain:contact>
<domain:contact type="tech">#{contact.code}</domain:contact>
</domain:create>
</create>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:legalDocument type="pdf">#{'test' * 2000}</eis:legalDocument>
</eis:extdata>
</extension>
</command>
</epp>
XML
assert_no_difference 'Domain.count' do
post epp_create_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
end
assert_epp_response :parameter_value_policy_error
end
def test_create_domain_with_array_of_not_unique_techs
now = Time.zone.parse('2010-07-05')
travel_to now
name = "new.#{dns_zones(:one).origin}"
contact = contacts(:john)
registrant = contact.becomes(Registrant)
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<create>
<domain:create xmlns:domain="https://epp.tld.ee/schema/domain-eis-1.0.xsd">
<domain:name>#{name}</domain:name>
<domain:registrant>#{registrant.code}</domain:registrant>
<domain:contact type="admin">#{contact.code}</domain:contact>
<domain:contact type="tech">#{contact.code}</domain:contact>
<domain:contact type="tech">#{contact.code}</domain:contact>
</domain:create>
</create>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:legalDocument type="pdf">#{'test' * 2000}</eis:legalDocument>
</eis:extdata>
</extension>
</command>
</epp>
XML
assert_no_difference 'Domain.count' do
post epp_create_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
end
assert_epp_response :parameter_value_policy_error
end
def test_create_domain_with_array_of_not_unique_admin_but_tech_another_one
now = Time.zone.parse('2010-07-05')
travel_to now
name = "new.#{dns_zones(:one).origin}"
contact = contacts(:john)
registrant = contact.becomes(Registrant)
contact_two = contacts(:william)
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<create>
<domain:create xmlns:domain="https://epp.tld.ee/schema/domain-eis-1.0.xsd">
<domain:name>#{name}</domain:name>
<domain:registrant>#{registrant.code}</domain:registrant>
<domain:contact type="admin">#{contact.code}</domain:contact>
<domain:contact type="admin">#{contact.code}</domain:contact>
<domain:contact type="tech">#{contact_two.code}</domain:contact>
</domain:create>
</create>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:legalDocument type="pdf">#{'test' * 2000}</eis:legalDocument>
</eis:extdata>
</extension>
</command>
</epp>
XML
assert_no_difference 'Domain.count' do
post epp_create_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
end
assert_epp_response :parameter_value_policy_error
end
def test_create_domain_with_array_of_not_unique_techs_but_admin_another_one
now = Time.zone.parse('2010-07-05')
travel_to now
name = "new.#{dns_zones(:one).origin}"
contact = contacts(:john)
registrant = contact.becomes(Registrant)
contact_two = contacts(:william)
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<create>
<domain:create xmlns:domain="https://epp.tld.ee/schema/domain-eis-1.0.xsd">
<domain:name>#{name}</domain:name>
<domain:registrant>#{registrant.code}</domain:registrant>
<domain:contact type="admin">#{contact_two.code}</domain:contact>
<domain:contact type="tech">#{contact.code}</domain:contact>
<domain:contact type="tech">#{contact.code}</domain:contact>
</domain:create>
</create>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:legalDocument type="pdf">#{'test' * 2000}</eis:legalDocument>
</eis:extdata>
</extension>
</command>
</epp>
XML
assert_no_difference 'Domain.count' do
post epp_create_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
end
assert_epp_response :parameter_value_policy_error
end
def test_registers_new_domain_with_required_attributes def test_registers_new_domain_with_required_attributes
now = Time.zone.parse('2010-07-05') now = Time.zone.parse('2010-07-05')
travel_to now travel_to now

View file

@ -3,6 +3,7 @@ require 'test_helper'
class EppDomainTransferRequestTest < EppTestCase class EppDomainTransferRequestTest < EppTestCase
def setup def setup
@domain = domains(:shop) @domain = domains(:shop)
@contact = contacts(:jane)
@new_registrar = registrars(:goodnames) @new_registrar = registrars(:goodnames)
@original_transfer_wait_time = Setting.transfer_wait_time @original_transfer_wait_time = Setting.transfer_wait_time
Setting.transfer_wait_time = 0 Setting.transfer_wait_time = 0
@ -12,6 +13,95 @@ class EppDomainTransferRequestTest < EppTestCase
Setting.transfer_wait_time = @original_transfer_wait_time Setting.transfer_wait_time = @original_transfer_wait_time
end end
def test_transfer_domain_with_contacts_if_registrant_and_tech_are_shared
@domain.tech_domain_contacts[0].update!(contact_id: @domain.registrant.id)
@domain.tech_domain_contacts[1].delete
@domain.reload
post epp_transfer_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_goodnames' }
assert_epp_response :completed_successfully
@domain.reload
tech = Contact.find_by(id: @domain.tech_domain_contacts[0].contact_id)
assert_equal @domain.contacts.where(original_id: @domain.registrant.original_id).count, 1
assert_equal tech.registrar_id, @domain.registrar.id
end
def test_transfer_domain_with_contacts_if_registrant_and_admin_are_shared
@domain.admin_domain_contacts[0].update!(contact_id: @domain.registrant.id)
@domain.tech_domain_contacts[0].update!(contact_id: @contact.id)
@domain.tech_domain_contacts[1].delete
@domain.reload
post epp_transfer_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_goodnames' }
assert_epp_response :completed_successfully
@domain.reload
admin = Contact.find_by(id: @domain.admin_domain_contacts[0].contact_id)
assert_equal @domain.contacts.where(original_id: @domain.registrant.original_id).count, 1
assert_equal admin.registrar_id, @domain.registrar.id
end
def test_transfer_domain_with_contacts_if_admin_and_tech_are_shared
@domain.admin_domain_contacts[0].update!(contact_id: @contact.id)
@domain.tech_domain_contacts[0].update!(contact_id: @contact.id)
@domain.tech_domain_contacts[1].delete
@domain.reload
post epp_transfer_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_goodnames' }
assert_epp_response :completed_successfully
@domain.reload
admin = Contact.find_by(id: @domain.admin_domain_contacts[0].contact_id)
tech = Contact.find_by(id: @domain.tech_domain_contacts[0].contact_id)
result_hash = @domain.contacts.pluck(:original_id).group_by(&:itself).transform_values(&:count)
assert result_hash[admin.original_id], 2
assert_equal admin.registrar_id, @domain.registrar.id
assert_equal tech.registrar_id, @domain.registrar.id
end
def test_transfer_domain_with_contacts_if_admin_and_tech_and_registrant_are_shared
@domain.tech_domain_contacts[0].update!(contact_id: @domain.registrant.id)
@domain.admin_domain_contacts[0].update!(contact_id: @domain.registrant.id)
@domain.tech_domain_contacts[1].delete
@domain.reload
post epp_transfer_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_goodnames' }
assert_epp_response :completed_successfully
@domain.reload
admin = Contact.find_by(id: @domain.admin_domain_contacts[0].contact_id)
tech = Contact.find_by(id: @domain.tech_domain_contacts[0].contact_id)
assert_equal @domain.contacts.where(original_id: @domain.registrant.original_id).count, 2
result_hash = @domain.contacts.pluck(:original_id).group_by(&:itself).transform_values(&:count)
assert result_hash[@domain.registrant.original_id], 2
assert_equal admin.registrar_id, @domain.registrar.id
assert_equal tech.registrar_id, @domain.registrar.id
end
def test_transfers_domain_at_once def test_transfers_domain_at_once
post epp_transfer_path, params: { frame: request_xml }, post epp_transfer_path, params: { frame: request_xml },
headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } headers: { 'HTTP_COOKIE' => 'session=api_goodnames' }

View file

@ -1,5 +1,4 @@
require "test_helper" require "test_helper"
class DomainUpdateConfirmJobTest < ActiveSupport::TestCase class DomainUpdateConfirmJobTest < ActiveSupport::TestCase
def setup def setup
super super
@ -19,6 +18,22 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase
super super
end end
def test_registrant_locked_domain
refute @domain.locked_by_registrant?
@domain.apply_registry_lock
assert @domain.locked_by_registrant?
assert_equal(@domain.registrar.notifications.last.text, "Domain #{@domain.name} has been locked by registrant")
end
def test_registrant_unlocked_domain
refute @domain.locked_by_registrant?
@domain.apply_registry_lock
assert @domain.locked_by_registrant?
@domain.remove_registry_lock
refute @domain.locked_by_registrant?
assert_equal(@domain.registrar.notifications.last.text, "Domain #{@domain.name} has been unlocked by registrant")
end
def test_rejected_registrant_verification_notifies_registrar def test_rejected_registrant_verification_notifies_registrar
DomainUpdateConfirmJob.perform_now(@domain.id, RegistrantVerification::REJECTED) DomainUpdateConfirmJob.perform_now(@domain.id, RegistrantVerification::REJECTED)

View file

@ -25,6 +25,7 @@ class DomainReleasableAuctionableTest < ActiveSupport::TestCase
def test_skips_auction_when_domains_is_blocked def test_skips_auction_when_domains_is_blocked
assert_equal 'shop.test', @domain.name assert_equal 'shop.test', @domain.name
blocked_domains(:one).update!(name: 'shop.test') blocked_domains(:one).update!(name: 'shop.test')
@domain.save!(validate: false)
@domain.release @domain.release
@ -34,6 +35,7 @@ class DomainReleasableAuctionableTest < ActiveSupport::TestCase
def test_skips_auction_when_domains_is_reserved def test_skips_auction_when_domains_is_reserved
assert_equal 'shop.test', @domain.name assert_equal 'shop.test', @domain.name
reserved_domains(:one).update!(name: 'shop.test') reserved_domains(:one).update!(name: 'shop.test')
@domain.save!(validate: false)
@domain.release @domain.release
@ -58,6 +60,24 @@ class DomainReleasableAuctionableTest < ActiveSupport::TestCase
end end
end end
def test_updates_whois_server
@domain.update!(delete_date: '2010-07-04')
travel_to Time.zone.parse('2010-07-05')
old_whois = @domain.whois_record
Domain.release_domains
assert_raises ActiveRecord::RecordNotFound do
old_whois.reload
end
whois_record = Whois::Record.find_by(name: @domain.name)
json = { "name"=>@domain.name,
"status"=>["AtAuction"],
"disclaimer"=> Setting.registry_whois_disclaimer }
assert_equal whois_record.json, json
end
def test_notifies_registrar def test_notifies_registrar
@domain.update!(delete_date: '2010-07-04') @domain.update!(delete_date: '2010-07-04')
travel_to Time.zone.parse('2010-07-05') travel_to Time.zone.parse('2010-07-05')

View file

@ -69,6 +69,12 @@ class DomainTest < ActiveSupport::TestCase
domain.name = 'xn--mnchen-3ya.test' domain.name = 'xn--mnchen-3ya.test'
assert domain.valid? assert domain.valid?
domain.name = '####'
assert domain.invalid?
domain.name = 'https://example.test'
assert domain.invalid?
end end
def test_invalid_when_name_is_already_taken def test_invalid_when_name_is_already_taken

View file

@ -38,6 +38,20 @@ class WhiteIpTest < ActiveSupport::TestCase
assert white_ip.valid? assert white_ip.valid?
end end
def test_validates_include_empty_ipv4
white_ip = WhiteIp.new
white_ip.ipv4 = nil
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 private
def valid_white_ip def valid_white_ip

View file

@ -4,6 +4,35 @@ class AdminAreaBankStatementTest < ApplicationSystemTestCase
setup do setup do
sign_in users(:admin) sign_in users(:admin)
travel_to Time.zone.parse('2010-07-05 00:30:00') travel_to Time.zone.parse('2010-07-05 00:30:00')
@invoice = invoices(:one)
end
def test_update_bank_statement
visit admin_bank_statement_path(id: @invoice.id)
click_link_or_button 'Add'
fill_in 'Description', with: 'Invoice with id 123'
fill_in 'Reference number', with: '1232'
fill_in 'Sum', with: '500'
fill_in 'Paid at', with: Time.zone.today.to_s
click_link_or_button 'Save'
assert_text 'Bank transaction'
click_link_or_button 'Edit'
fill_in 'Description', with: 'Invoice with id 123'
click_link_or_button 'Save'
assert_text 'Record updated'
end
def test_bind_bank
visit admin_bank_statement_path(id: @invoice.id)
click_link_or_button 'Bind invoices'
assert_text 'No invoices were binded'
end end
def test_can_create_statement_manually def test_can_create_statement_manually

View file

@ -8,6 +8,17 @@ class AdminContactsTest < ApplicationSystemTestCase
sign_in users(:admin) sign_in users(:admin)
end end
def test_update_contact
visit admin_contact_path(id: @contact.id)
assert_text "#{@contact.name}"
click_on 'Edit statuses'
assert_text "Edit: #{@contact.name}"
click_on 'Save'
assert_text 'Contact updated'
end
def test_display_list def test_display_list
visit admin_contacts_path visit admin_contacts_path

View file

@ -0,0 +1,18 @@
require 'application_system_test_case'
class AdminAreaCsvTest < ApplicationSystemTestCase
setup do
sign_in users(:admin)
end
def test_downloads_domain_list_as_csv
search_params = {"valid_to_lteq"=>nil}
expected_csv = Domain.includes(:registrar, :registrant).search(search_params).result.to_csv
travel_to Time.zone.parse('2010-07-05 10:30')
visit admin_domains_url
click_link('CSV')
assert_equal "attachment; filename=\"domains.csv\"; filename*=UTF-8''domains.csv", response_headers['Content-Disposition']
assert_equal expected_csv, page.body
end
end

View file

@ -15,7 +15,7 @@ class AdminAreaDomainsLegalDocTest < ApplicationSystemTestCase
def test_absent_doc_downloading_without_errors def test_absent_doc_downloading_without_errors
visit admin_domain_url(@domain) visit admin_domain_url(@domain)
assert_nothing_raised do assert_nothing_raised do
click_on "#{@document.created_at}" click_on "#{@document.created_at}", match: :first
end end
end end
end end

View file

@ -0,0 +1,28 @@
require 'application_system_test_case'
class RegistrarAccountActivitiesTest < ApplicationSystemTestCase
setup do
@registrar = registrars(:bestnames)
sign_in users(:api_bestnames)
end
def test_show_account_activity_page
account_activities(:one).update(sum: "123.00")
visit registrar_account_activities_path
assert_text 'Account activity'
end
def test_download_account_activity
now = Time.zone.parse('2010-07-05 08:00')
travel_to now
account_activities(:one).update(sum: "123.00")
get registrar_account_activities_path(format: :csv)
assert_response :ok
assert_equal "text/csv", response.headers['Content-Type']
assert_equal %(attachment; filename="account_activities_#{Time.zone.now.to_formatted_s(:number)}.csv"; filename*=UTF-8''account_activities_#{Time.zone.now.to_formatted_s(:number)}.csv),
response.headers['Content-Disposition']
assert_not_empty response.body
end
end

View file

@ -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

View file

@ -16,8 +16,8 @@ class RegistrarAreaTechContactBulkChangeTest < ApplicationSystemTestCase
visit registrar_domains_url visit registrar_domains_url
click_link 'Bulk change' click_link 'Bulk change'
fill_in 'Current contact ID', with: 'william-001' find('.current_tech_contact').fill_in 'Current contact ID', with: 'william-001'
fill_in 'New contact ID', with: 'john-001' find('.new_tech_contact').fill_in 'New contact ID', with: 'john-001'
click_on 'Replace technical contacts' click_on 'Replace technical contacts'
assert_requested request_stub assert_requested request_stub
@ -36,8 +36,8 @@ class RegistrarAreaTechContactBulkChangeTest < ApplicationSystemTestCase
visit registrar_domains_url visit registrar_domains_url
click_link 'Bulk change' click_link 'Bulk change'
fill_in 'Current contact ID', with: 'william-001' find('.current_tech_contact').fill_in 'Current contact ID', with: 'william-001'
fill_in 'New contact ID', with: 'john-001' find('.new_tech_contact').fill_in 'New contact ID', with: 'john-001'
click_on 'Replace technical contacts' click_on 'Replace technical contacts'
assert_text 'epic fail' assert_text 'epic fail'