Merge remote-tracking branch 'origin/registry-660' into registry-661

# Conflicts:
#	db/structure.sql
#	doc/repp-doc.md
This commit is contained in:
Artur Beljajev 2018-01-30 00:58:49 +02:00
commit 56e3f236bc
156 changed files with 2085 additions and 1276 deletions

View file

@ -54,14 +54,14 @@ class Ability
# can(:create, :epp_request)
# Epp::Domain
can(:info, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || pw.blank? ? true : d.auth_info == pw }
can(:info, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || pw.blank? ? true : d.transfer_code == pw }
can(:check, Epp::Domain)
can(:create, Epp::Domain)
can(:renew, Epp::Domain) { |d| d.registrar_id == @user.registrar_id }
can(:update, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.auth_info == pw }
can(:transfer, Epp::Domain) { |d, pw| d.auth_info == pw }
can(:view_password, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.auth_info == pw }
can(:delete, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.auth_info == pw }
can(:update, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw }
can(:transfer, Epp::Domain) { |d, pw| d.transfer_code == pw }
can(:view_password, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw }
can(:delete, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw }
# Epp::Contact
can(:info, Epp::Contact) { |c, pw| c.registrar_id == @user.registrar_id || pw.blank? ? true : c.auth_info == pw }

View file

@ -19,24 +19,17 @@ authentication using electronic ID. Association through a business organisation
=end
class BusinessRegistryCache < ActiveRecord::Base
# 1. load domains by business
# 2. load domains by person
def associated_contacts
contact_ids = Contact.where(ident_type: 'org', ident: associated_businesses, ident_country_code: 'EE').pluck(:id)
contact_ids += Contact.where(ident_type: 'priv', ident: ident, ident_country_code: ident_country_code).pluck(:id)
contact_ids
end
def associated_domain_ids
contact_ids = Contact.where(ident_type: 'org', ident: associated_businesses, ident_country_code: ident_country_code).pluck(:id)
contact_ids += Contact.where(ident_type: 'priv', ident: ident, ident_country_code: ident_country_code).pluck(:id)
domain_ids = []
contact_ids = associated_contacts
unless contact_ids.blank?
domain_ids = DomainContact.distinct.where(contact_id: contact_ids).pluck(:domain_id)
end
domain_ids += Domain.where(registrant_id: contact_ids).pluck(:id)
domain_ids
end
@ -69,15 +62,5 @@ class BusinessRegistryCache < ActiveRecord::Base
def business_registry
Soap::Arireg.new
end
def purge
STDOUT << "#{Time.zone.now.utc} - Starting Purge of old BusinessRegistry data from cache\n" unless Rails.env.test?
purged = 0
BusinessRegistryCache.where('retrieved_on < ?',
Time.zone.now < Setting.days_to_keep_business_registry_cache.days).each do |br|
br.destroy and purged += 1
end
STDOUT << "#{Time.zone.now.utc} - Finished purging #{purged} old BusinessRegistry cache items\n" unless Rails.env.test?
end
end
end

View file

@ -0,0 +1,28 @@
module Concerns::Contact::Transferable
extend ActiveSupport::Concern
included do
validates :auth_info, presence: true
after_initialize :generate_auth_info, if: 'new_record? && auth_info.blank?'
end
def transfer(new_registrar)
new_contact = self.dup
new_contact.registrar = new_registrar
new_contact.original = self
new_contact.code = nil
new_contact.regenerate_code
new_contact.regenerate_auth_info
new_contact.remove_address unless self.class.address_processing?
new_contact.save!
new_contact
end
protected
def generate_auth_info
self.auth_info = SecureRandom.hex(11)
end
alias_method :regenerate_auth_info, :generate_auth_info
end

View file

@ -0,0 +1,68 @@
module Concerns::Domain::Transferable
extend ActiveSupport::Concern
included do
after_initialize :generate_transfer_code, if: 'new_record? && transfer_code.blank?'
end
def transfer(new_registrar)
old_registrar = registrar
self.registrar = new_registrar
regenerate_transfer_code
contact_codes = contacts.pluck(:code).sort.uniq
registrant_code = registrant.code
transaction do
old_registrar.messages.create!(
body: I18n.t('domain_transfer_was_approved', contacts: contact_codes, registrant: registrant_code),
attached_obj_id: id,
attached_obj_type: self.class.name
)
domain_transfers.create!(
transfer_requested_at: Time.zone.now,
old_registrar: old_registrar,
new_registrar: new_registrar
)
transfer_contacts(new_registrar)
save!
end
end
private
def generate_transfer_code
self.transfer_code = SecureRandom.hex
end
alias_method :regenerate_transfer_code, :generate_transfer_code
def transfer_contacts(new_registrar)
transfer_registrant(new_registrar)
transfer_domain_contacts(new_registrar)
end
def transfer_registrant(new_registrar)
return if registrant.registrar == new_registrar
self.registrant = registrant.transfer(new_registrar)
end
def transfer_domain_contacts(new_registrar)
copied_ids = []
contacts.each do |contact|
next if copied_ids.include?(contact.id) || contact.registrar == new_registrar
if registrant_id_was == contact.id # registrant was copied previously, do not copy it again
oc = OpenStruct.new(id: registrant_id)
else
oc = contact.transfer(new_registrar)
end
domain_contacts.where(contact_id: contact.id).update_all({ contact_id: oc.id }) # n+1 workaround
copied_ids << contact.id
end
end
end

View file

@ -2,7 +2,9 @@ class Contact < ActiveRecord::Base
include Versions # version/contact_version.rb
include EppErrors
include UserEvents
include Concerns::Contact::Transferable
belongs_to :original, class_name: self.name
belongs_to :registrar, required: true
has_many :domain_contacts
has_many :domains, through: :domain_contacts
@ -43,7 +45,6 @@ class Contact < ActiveRecord::Base
before_validation :to_upcase_country_code
before_validation :strip_email
before_create :generate_auth_info
before_update :manage_emails
composed_of :identifier,
@ -79,7 +80,6 @@ class Contact < ActiveRecord::Base
PASSPORT = 'passport'
attr_accessor :deliver_emails
attr_accessor :domain_transfer # hack but solves problem faster
#
# STATUSES
@ -313,16 +313,6 @@ class Contact < ActiveRecord::Base
!org?
end
def generate_auth_info
return if @generate_auth_info_disabled
return if auth_info.present?
self.auth_info = SecureRandom.hex(11)
end
# def auth_info=(pw)
# self[:auth_info] = pw if new_record?
# end
def code=(code)
self[:code] = code if new_record? # cannot change code later
end
@ -346,6 +336,8 @@ class Contact < ActiveRecord::Base
end
# rubocop:enable Metrics/CyclomaticComplexity
alias_method :regenerate_code, :generate_code
def country
Country.new(country_code)
end

View file

@ -118,7 +118,7 @@ module Depp
current_user.request(epp_xml.transfer({
name: { value: params[:domain_name] },
authInfo: { pw: { value: params[:password] } }
authInfo: { pw: { value: params[:transfer_code] } }
}, op, Domain.construct_custom_params_hash(params)))
end

View file

@ -36,39 +36,6 @@ module Depp
Nokogiri::XML(e.response_xml.to_s).remove_namespaces!
end
# rubocop:disable Metrics/AbcSize
def repp_request(path, params = {})
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
repp_url = Rails.env.test? ? 'http://localhost:8989/repp/v1/' : ENV['repp_url']
uri = URI.parse("#{repp_url}#{path}")
uri.query = URI.encode_www_form(params)
req = Net::HTTP::Get.new(uri)
req.basic_auth tag, password
res = 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(req)
end
ret = OpenStruct.new(code: res.code)
ret.parsed_body = JSON.parse(res.body) if res.body.present?
if ret.parsed_body && ret.parsed_body['error']
ret.message = ret.parsed_body['error']
else
ret.message = res.message
end
ret
end
# rubocop:enable Metrics/AbcSize
private
# rubocop:disable Metrics/AbcSize

View file

@ -6,6 +6,7 @@ class Domain < ActiveRecord::Base
include Concerns::Domain::Activatable
include Concerns::Domain::ForceDelete
include Concerns::Domain::Deletable
include Concerns::Domain::Transferable
has_paper_trail class_name: "DomainVersion", meta: { children: :children_log }
@ -79,9 +80,7 @@ class Domain < ActiveRecord::Base
self.status_notes = {} if status_notes.nil?
end
before_create :generate_auth_info
before_create -> { self.reserved = in_reserved_list?; nil }
before_save :manage_automatic_statuses
before_save :touch_always_version
def touch_always_version
@ -105,6 +104,7 @@ class Domain < ActiveRecord::Base
validates :name_dirty, domain_name: true, uniqueness: true
validates :puny_label, length: { maximum: 63 }
validates :period, presence: true, numericality: { only_integer: true }
validates :transfer_code, presence: true
validate :validate_reservation
def validate_reservation
@ -497,19 +497,6 @@ class Domain < ActiveRecord::Base
Registrant.find_by(id: pending_json['new_registrant_id'])
end
def generate_auth_info
return if auth_info.present?
generate_auth_info!
end
# rubocop:disable Lint/Loop
def generate_auth_info!
begin
self.auth_info = SecureRandom.hex
end while self.class.exists?(auth_info: auth_info)
end
# rubocop:enable Lint/Loop
def set_graceful_expired
self.outzone_at = expire_time + self.class.expire_warning_period
self.delete_at = outzone_at + self.class.redemption_grace_period
@ -672,6 +659,12 @@ class Domain < ActiveRecord::Base
pending_json['new_registrant_id']
end
def as_json(_options)
hash = super
hash['auth_info'] = hash.delete('transfer_code') # API v1 requirement
hash
end
def self.to_csv
CSV.generate do |csv|
csv << column_names

View file

@ -1,16 +1,13 @@
class DomainTransfer < ActiveRecord::Base
include Versions # version/domain_transfer_version.rb
belongs_to :domain
belongs_to :transfer_from, class_name: 'Registrar'
belongs_to :transfer_to, class_name: 'Registrar'
belongs_to :old_registrar, class_name: 'Registrar'
belongs_to :new_registrar, class_name: 'Registrar'
PENDING = 'pending'
CLIENT_APPROVED = 'clientApproved'
CLIENT_CANCELLED = 'clientCancelled'
CLIENT_REJECTED = 'clientRejected'
SERVER_APPROVED = 'serverApproved'
SERVER_CANCELLED = 'serverCancelled'
before_create :set_wait_until
def set_wait_until
@ -39,20 +36,8 @@ class DomainTransfer < ActiveRecord::Base
status == PENDING
end
def approve_as_client
transaction do
self.status = DomainTransfer::CLIENT_APPROVED
self.transferred_at = Time.zone.now
save
domain.generate_auth_info
domain.registrar = transfer_to
domain.save(validate: false)
end
end
def notify_losing_registrar(contacts, registrant)
transfer_from.messages.create!(
old_registrar.messages.create!(
body: I18n.t('domain_transfer_was_approved', contacts: contacts, registrant: registrant),
attached_obj_id: id,
attached_obj_type: self.class.to_s

View file

@ -100,7 +100,7 @@ class Epp::Domain < Domain
[:puny_label, :too_long, { obj: 'name', val: name_puny }]
],
'2201' => [ # Authorisation error
[:auth_info, :wrong_pw]
[:transfer_code, :wrong_pw]
],
'2202' => [
[:base, :invalid_auth_information_reserved]
@ -182,7 +182,7 @@ class Epp::Domain < Domain
# at[:domain_statuses_attributes] = domain_statuses_attrs(frame, action)
pw = frame.css('authInfo > pw').text
at[:auth_info] = pw if pw.present?
at[:transfer_code] = pw if pw.present?
if new_record?
dnskey_frame = frame.css('extension create')
@ -641,47 +641,6 @@ class Epp::Domain < Domain
end
end
# TODO: Eager load problems here. Investigate how it's possible not to query contact again
# Check if versioning works with update_column
def transfer_contacts(registrar_id)
transfer_registrant(registrar_id)
transfer_domain_contacts(registrar_id)
end
def copy_and_transfer_contact(contact_id, registrar_id)
c = Contact.find(contact_id) # n+1 workaround
oc = c.deep_clone
oc.code = nil
oc.registrar_id = registrar_id
oc.copy_from_id = c.id
oc.generate_code
oc.domain_transfer = true
oc.remove_address unless Contact.address_processing?
oc.save!(validate: false)
oc
end
def transfer_registrant(registrar_id)
return if registrant.registrar_id == registrar_id
self.registrant_id = copy_and_transfer_contact(registrant_id, registrar_id).id
end
def transfer_domain_contacts(registrar_id)
copied_ids = []
contacts.each do |c|
next if copied_ids.include?(c.id) || c.registrar_id == registrar_id
if registrant_id_was == c.id # registrant was copied previously, do not copy it again
oc = OpenStruct.new(id: registrant_id)
else
oc = copy_and_transfer_contact(c.id, registrar_id)
end
domain_contacts.where(contact_id: c.id).update_all({ contact_id: oc.id }) # n+1 workaround
copied_ids << c.id
end
end
# rubocop: enable Metrics/PerceivedComplexity
# rubocop: enable Metrics/CyclomaticComplexity
# rubocop: disable Metrics/MethodLength
@ -707,8 +666,8 @@ class Epp::Domain < Domain
transaction do
dt = domain_transfers.create!(
transfer_requested_at: Time.zone.now,
transfer_to: current_user.registrar,
transfer_from: registrar
old_registrar: registrar,
new_registrar: current_user.registrar
)
if dt.pending?
@ -720,9 +679,9 @@ class Epp::Domain < Domain
end
if dt.approved?
transfer_contacts(current_user.registrar_id)
transfer_contacts(current_user.registrar)
dt.notify_losing_registrar(old_contact_codes, old_registrant_code)
generate_auth_info!
regenerate_transfer_code
self.registrar = current_user.registrar
end
@ -737,7 +696,7 @@ class Epp::Domain < Domain
def approve_transfer(frame, current_user)
pt = pending_transfer
if current_user.registrar != pt.transfer_from
if current_user.registrar != pt.old_registrar
throw :epp_error, {
msg: I18n.t('transfer_can_be_approved_only_by_current_registrar'),
code: '2304'
@ -750,9 +709,9 @@ class Epp::Domain < Domain
transferred_at: Time.zone.now
)
transfer_contacts(pt.transfer_to_id)
generate_auth_info
self.registrar = pt.transfer_to
transfer_contacts(pt.new_registrar)
regenerate_transfer_code
self.registrar = pt.new_registrar
attach_legal_document(self.class.parse_legal_document_from_frame(frame))
save!(validate: false)
@ -763,7 +722,7 @@ class Epp::Domain < Domain
def reject_transfer(frame, current_user)
pt = pending_transfer
if current_user.registrar != pt.transfer_from
if current_user.registrar != pt.old_registrar
throw :epp_error, {
msg: I18n.t('transfer_can_be_rejected_only_by_current_registrar'),
code: '2304'
@ -872,7 +831,7 @@ class Epp::Domain < Domain
# For domain transfer
def authenticate(pw)
errors.add(:auth_info, :wrong_pw) if pw != auth_info
errors.add(:transfer_code, :wrong_pw) if pw != transfer_code
errors.empty?
end

View file

@ -140,8 +140,8 @@ class Registrar < ActiveRecord::Base
def domain_transfers
at = DomainTransfer.arel_table
DomainTransfer.where(
at[:transfer_to_id].eq(id).or(
at[:transfer_from_id].eq(id)
at[:new_registrar_id].eq(id).or(
at[:old_registrar_id].eq(id)
)
)
end

View file

@ -1,5 +0,0 @@
class DomainTransferVersion < PaperTrail::Version
include VersionSession
self.table_name = :log_domain_transfers
self.sequence_name = :log_domain_transfers_id_seq
end