mirror of
https://github.com/internetee/registry.git
synced 2025-06-08 05:34:46 +02:00
809 lines
23 KiB
Ruby
809 lines
23 KiB
Ruby
require 'deserializers/xml/legal_document'
|
|
|
|
class Epp::Domain < Domain
|
|
include EppErrors
|
|
|
|
# TODO: remove this spagetti once data in production is correct.
|
|
attr_accessor :is_renewal, :is_transfer
|
|
|
|
before_validation :manage_permissions
|
|
|
|
def manage_permissions
|
|
return if is_admin # this bad hack for 109086524, refactor later
|
|
return true if is_transfer || is_renewal
|
|
return unless update_prohibited?
|
|
|
|
stat = (statuses & (DomainStatus::UPDATE_PROHIBIT_STATES + DomainStatus::DELETE_PROHIBIT_STATES)).first
|
|
add_epp_error('2304', 'status', stat, I18n.t(:object_status_prohibits_operation))
|
|
throw(:abort)
|
|
end
|
|
|
|
after_validation :validate_contacts
|
|
def validate_contacts
|
|
return true if is_transfer
|
|
|
|
ok = true
|
|
active_admins = admin_domain_contacts.select { |x| !x.marked_for_destruction? }
|
|
active_techs = tech_domain_contacts.select { |x| !x.marked_for_destruction? }
|
|
|
|
# validate registrant here as well
|
|
([Contact.find_by(code: registrant.code)] + active_admins + active_techs).each do |x|
|
|
unless x.valid?
|
|
add_epp_error('2304', nil, nil, I18n.t(:contact_is_not_valid, value: x.code))
|
|
ok = false
|
|
end
|
|
end
|
|
ok
|
|
end
|
|
|
|
class << self
|
|
def new_from_epp(frame, current_user)
|
|
domain = Epp::Domain.new
|
|
domain.attributes = domain.attrs_from(frame, current_user)
|
|
domain.attach_default_contacts
|
|
|
|
period = domain.period.to_i
|
|
plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym
|
|
expire_time = (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day
|
|
domain.expire_time = expire_time
|
|
|
|
domain
|
|
end
|
|
end
|
|
|
|
def epp_code_map
|
|
{
|
|
'2002' => [ # Command use error
|
|
%i[base domain_already_belongs_to_the_querying_registrar],
|
|
],
|
|
'2003' => [ # Required parameter missing
|
|
%i[registrant blank],
|
|
%i[registrar blank],
|
|
%i[base required_parameter_missing_reserved],
|
|
%i[base required_parameter_missing_disputed],
|
|
],
|
|
'2004' => [ # Parameter value range error
|
|
[:dnskeys, :out_of_range,
|
|
{
|
|
min: Setting.dnskeys_min_count,
|
|
max: Setting.dnskeys_max_count
|
|
}
|
|
],
|
|
[:admin_contacts, :out_of_range,
|
|
{
|
|
min: Setting.admin_contacts_min_count,
|
|
max: Setting.admin_contacts_max_count
|
|
}
|
|
],
|
|
[:tech_contacts, :out_of_range,
|
|
{
|
|
min: Setting.tech_contacts_min_count,
|
|
max: Setting.tech_contacts_max_count
|
|
}
|
|
]
|
|
],
|
|
'2005' => [ # Parameter value syntax error
|
|
[:name_dirty, :invalid, { obj: 'name', val: name_dirty }],
|
|
[:puny_label, :too_long, { obj: 'name', val: name_puny }]
|
|
],
|
|
'2201' => [ # Authorisation error
|
|
%i[transfer_code wrong_pw],
|
|
],
|
|
'2202' => [
|
|
%i[base invalid_auth_information_reserved],
|
|
%i[base invalid_auth_information_disputed],
|
|
],
|
|
'2302' => [ # Object exists
|
|
[:name_dirty, :taken, { value: { obj: 'name', val: name_dirty } }],
|
|
[:name_dirty, :reserved, { value: { obj: 'name', val: name_dirty } }],
|
|
[:name_dirty, :blocked, { value: { obj: 'name', val: name_dirty } }]
|
|
],
|
|
'2304' => [ # Object status prohibits operation
|
|
[:base, :domain_status_prohibits_operation]
|
|
],
|
|
'2306' => [ # Parameter policy error
|
|
[:base, :ds_data_with_key_not_allowed],
|
|
[:base, :ds_data_not_allowed],
|
|
[:base, :key_data_not_allowed],
|
|
[:period, :not_a_number],
|
|
[:period, :not_an_integer],
|
|
[:registrant, :cannot_be_missing]
|
|
],
|
|
'2308' => [
|
|
[:base, :domain_name_blocked, { value: { obj: 'name', val: name_dirty } }],
|
|
[:nameservers, :out_of_range,
|
|
{
|
|
min: Setting.ns_min_count,
|
|
max: Setting.ns_max_count
|
|
}
|
|
],
|
|
]
|
|
}
|
|
end
|
|
|
|
def attach_default_contacts
|
|
return if registrant.blank?
|
|
tech_contacts << registrant if tech_domain_contacts.blank?
|
|
admin_contacts << registrant if admin_domain_contacts.blank? && !registrant.org?
|
|
end
|
|
|
|
def attrs_from(frame, current_user, action = nil)
|
|
at = {}.with_indifferent_access
|
|
|
|
registrant_frame = frame.css('registrant').first
|
|
code = registrant_frame.try(:text)
|
|
if code.present?
|
|
if action == 'chg' && registrant_change_prohibited?
|
|
add_epp_error('2304', "status", DomainStatus::SERVER_REGISTRANT_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation))
|
|
end
|
|
regt = Registrant.find_by(code: code)
|
|
if regt
|
|
at[:registrant_id] = regt.id
|
|
else
|
|
add_epp_error('2303', 'registrant', code, [:registrant, :not_found])
|
|
end
|
|
else
|
|
add_epp_error('2306', nil, nil, [:registrant, :cannot_be_missing])
|
|
end if registrant_frame
|
|
|
|
|
|
at[:name] = frame.css('name').text if new_record?
|
|
at[:registrar_id] = current_user.registrar.try(:id)
|
|
|
|
period = frame.css('period').text
|
|
at[:period] = (period.to_i == 0) ? 1 : period.to_i
|
|
|
|
at[:period_unit] = Epp::Domain.parse_period_unit_from_frame(frame) || 'y'
|
|
|
|
at[:reserved_pw] = frame.css('reserved > pw').text
|
|
|
|
# at[:statuses] = domain_statuses_attrs(frame, action)
|
|
at[:nameservers_attributes] = nameservers_attrs(frame, action)
|
|
at[:admin_domain_contacts_attributes] = admin_domain_contacts_attrs(frame, action)
|
|
at[:tech_domain_contacts_attributes] = tech_domain_contacts_attrs(frame, action)
|
|
|
|
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
|
|
at[:transfer_code] = pw if pw.present?
|
|
|
|
if new_record?
|
|
dnskey_frame = frame.css('extension create')
|
|
else
|
|
dnskey_frame = frame
|
|
end
|
|
|
|
at[:dnskeys_attributes] = dnskeys_attrs(dnskey_frame, action)
|
|
|
|
at
|
|
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
|
|
# if something goes wrong - raise Rollback error
|
|
def add_legal_file_to_new frame
|
|
legal_document_data = ::Deserializers::Xml::LegalDocument.new(frame).call
|
|
return unless legal_document_data
|
|
return if legal_document_data[:body].starts_with?(ENV['legal_documents_dir'])
|
|
|
|
doc = LegalDocument.create(documentable_type: Domain, document_type: legal_document_data[:type],
|
|
body: legal_document_data[:body])
|
|
self.legal_documents = [doc]
|
|
|
|
frame.css("legalDocument").first.content = doc.path if doc&.persisted?
|
|
self.legal_document_id = doc.id
|
|
end
|
|
|
|
def nameservers_attrs(frame, action)
|
|
ns_list = nameservers_from(frame)
|
|
|
|
if action == 'rem'
|
|
to_destroy = []
|
|
ns_list.each do |ns_attrs|
|
|
nameserver = nameservers.find_by_hash_params(ns_attrs).first
|
|
if nameserver.blank?
|
|
add_epp_error('2303', 'hostAttr', ns_attrs[:hostname], [:nameservers, :not_found])
|
|
else
|
|
to_destroy << {
|
|
id: nameserver.id,
|
|
_destroy: 1
|
|
}
|
|
end
|
|
end
|
|
|
|
return to_destroy
|
|
else
|
|
return ns_list
|
|
end
|
|
end
|
|
|
|
def nameservers_from(frame)
|
|
res = []
|
|
frame.css('hostAttr').each do |x|
|
|
host_attr = {
|
|
hostname: x.css('hostName').first.try(:text),
|
|
ipv4: x.css('hostAddr[ip="v4"]').map(&:text).compact,
|
|
ipv6: x.css('hostAddr[ip="v6"]').map(&:text).compact
|
|
}
|
|
|
|
res << host_attr.delete_if { |_k, v| v.blank? }
|
|
end
|
|
|
|
res
|
|
end
|
|
|
|
def admin_domain_contacts_attrs(frame, action)
|
|
admin_attrs = domain_contact_attrs_from(frame, action, 'admin')
|
|
|
|
if admin_attrs.present? && admin_change_prohibited?
|
|
add_epp_error('2304', 'admin', DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation))
|
|
return []
|
|
end
|
|
|
|
case action
|
|
when 'rem'
|
|
return destroy_attrs(admin_attrs, admin_domain_contacts)
|
|
else
|
|
return admin_attrs
|
|
end
|
|
end
|
|
|
|
def tech_domain_contacts_attrs(frame, action)
|
|
tech_attrs = domain_contact_attrs_from(frame, action, 'tech')
|
|
|
|
if tech_attrs.present? && tech_change_prohibited?
|
|
add_epp_error('2304', 'tech', DomainStatus::SERVER_TECH_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation))
|
|
return []
|
|
end
|
|
|
|
case action
|
|
when 'rem'
|
|
return destroy_attrs(tech_attrs, tech_domain_contacts)
|
|
else
|
|
return tech_attrs
|
|
end
|
|
end
|
|
|
|
def destroy_attrs(attrs, dcontacts)
|
|
destroy_attrs = []
|
|
attrs.each do |at|
|
|
domain_contact_id = dcontacts.find_by(contact_id: at[:contact_id]).try(:id)
|
|
|
|
unless domain_contact_id
|
|
add_epp_error('2303', 'contact', at[:contact_code_cache], [:domain_contacts, :not_found])
|
|
next
|
|
end
|
|
|
|
destroy_attrs << {
|
|
id: domain_contact_id,
|
|
_destroy: 1
|
|
}
|
|
end
|
|
|
|
destroy_attrs
|
|
end
|
|
|
|
def domain_contact_attrs_from(frame, action, type)
|
|
attrs = []
|
|
frame.css('contact').each do |x|
|
|
next if x['type'] != type
|
|
|
|
c = Epp::Contact.find_by_epp_code(x.text)
|
|
unless c
|
|
add_epp_error('2303', 'contact', x.text, [:domain_contacts, :not_found])
|
|
next
|
|
end
|
|
|
|
if action != 'rem'
|
|
if x['type'] == 'admin' && c.org?
|
|
add_epp_error('2306', 'contact', x.text, [:domain_contacts, :admin_contact_can_be_only_private_person])
|
|
next
|
|
end
|
|
end
|
|
|
|
attrs << {
|
|
contact_id: c.id,
|
|
contact_code_cache: c.code
|
|
}
|
|
end
|
|
|
|
attrs
|
|
end
|
|
|
|
def dnskeys_attrs(frame, action)
|
|
keys = []
|
|
return keys if frame.blank?
|
|
inf_data = DnsSecKeys.new(frame)
|
|
add_epp_error('2005', nil, nil, %i[dnskeys invalid]) if not_base64?(inf_data)
|
|
|
|
if action == 'rem' &&
|
|
frame.css('rem > all').first.try(:text) == 'true'
|
|
keys = inf_data.mark_destroy_all dnskeys
|
|
else
|
|
if Setting.key_data_allowed
|
|
errors.add(:base, :ds_data_not_allowed) if inf_data.ds_data.present?
|
|
keys = inf_data.key_data
|
|
end
|
|
if Setting.ds_data_allowed
|
|
errors.add(:base, :key_data_not_allowed) if inf_data.key_data.present?
|
|
keys = inf_data.ds_data
|
|
end
|
|
if action == 'rem'
|
|
keys = inf_data.mark_destroy(dnskeys)
|
|
add_epp_error('2303', nil, nil, [:dnskeys, :not_found]) if keys.include? nil
|
|
end
|
|
end
|
|
errors.any? ? [] : keys
|
|
end
|
|
|
|
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
|
|
def initialize(frame)
|
|
@key_data = []
|
|
@ds_data = []
|
|
# schema validation prevents both in the same parent node
|
|
if frame.css('dsData').present?
|
|
ds_data_from frame
|
|
else
|
|
frame.css('keyData').each do |key|
|
|
@key_data.append key_data_from(key)
|
|
end
|
|
end
|
|
end
|
|
|
|
attr_reader :key_data
|
|
attr_reader :ds_data
|
|
|
|
def mark_destroy_all(dns_keys)
|
|
# if transition support required mark_destroy dns_keys when has ds/key values otherwise ...
|
|
dns_keys.map { |inf_data| mark inf_data }
|
|
end
|
|
|
|
def mark_destroy(dns_keys)
|
|
(ds_data.present? ? ds_filter(dns_keys) : kd_filter(dns_keys)).map do |inf_data|
|
|
inf_data.blank? ? nil : mark(inf_data)
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
KEY_INTERFACE = {flags: 'flags', protocol: 'protocol', alg: 'alg', public_key: 'pubKey' }
|
|
DS_INTERFACE =
|
|
{ ds_key_tag: 'keyTag',
|
|
ds_alg: 'alg',
|
|
ds_digest_type: 'digestType',
|
|
ds_digest: 'digest'
|
|
}
|
|
|
|
def xm_copy(frame, map)
|
|
result = {}
|
|
map.each do |key, elem|
|
|
result[key] = frame.css(elem).first.try(:text)
|
|
end
|
|
result
|
|
end
|
|
|
|
def key_data_from(frame)
|
|
xm_copy frame, KEY_INTERFACE
|
|
end
|
|
|
|
def ds_data_from(frame)
|
|
frame.css('dsData').each do |ds_data|
|
|
key = ds_data.css('keyData')
|
|
ds = xm_copy ds_data, DS_INTERFACE
|
|
ds.merge(key_data_from key) if key.present?
|
|
@ds_data << ds
|
|
end
|
|
end
|
|
|
|
def ds_filter(dns_keys)
|
|
@ds_data.map do |ds|
|
|
dns_keys.find_by(ds.slice(*DS_INTERFACE.keys))
|
|
end
|
|
end
|
|
|
|
def kd_filter(dns_keys)
|
|
@key_data.map do |key|
|
|
dns_keys.find_by(key)
|
|
end
|
|
end
|
|
|
|
def mark(inf_data)
|
|
{ id: inf_data.id, _destroy: 1 }
|
|
end
|
|
end
|
|
|
|
def domain_statuses_attrs(frame, action)
|
|
status_list = domain_status_list_from(frame)
|
|
if action == 'rem'
|
|
to_destroy = []
|
|
status_list.each do |x|
|
|
if statuses.include?(x)
|
|
to_destroy << x
|
|
else
|
|
add_epp_error('2303', 'status', x, %i[statuses not_found])
|
|
end
|
|
end
|
|
|
|
return to_destroy
|
|
else
|
|
return status_list
|
|
end
|
|
end
|
|
|
|
def domain_status_list_from(frame)
|
|
status_list = []
|
|
|
|
frame.css('status').each do |x|
|
|
unless DomainStatus::CLIENT_STATUSES.include?(x['s'])
|
|
add_epp_error('2303', 'status', x['s'], %i[statuses not_found])
|
|
next
|
|
end
|
|
|
|
status_list << x['s']
|
|
end
|
|
|
|
status_list
|
|
end
|
|
|
|
|
|
def update(frame, current_user, verify = true)
|
|
return super if frame.blank?
|
|
|
|
if discarded? || statuses_blocks_update?
|
|
add_epp_error('2304', nil, nil, 'Object status prohibits operation')
|
|
return
|
|
end
|
|
|
|
at = {}.with_indifferent_access
|
|
at.deep_merge!(attrs_from(frame.css('chg'), current_user, 'chg'))
|
|
at.deep_merge!(attrs_from(frame.css('rem'), current_user, 'rem'))
|
|
|
|
if doc = attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call)
|
|
frame.css("legalDocument").first.content = doc.path if doc&.persisted?
|
|
self.legal_document_id = doc.id
|
|
end
|
|
|
|
at_add = attrs_from(frame.css('add'), current_user, 'add')
|
|
at[:nameservers_attributes] += at_add[:nameservers_attributes]
|
|
at[:admin_domain_contacts_attributes] += at_add[:admin_domain_contacts_attributes]
|
|
at[:tech_domain_contacts_attributes] += at_add[:tech_domain_contacts_attributes]
|
|
at[:dnskeys_attributes] += at_add[:dnskeys_attributes]
|
|
at[:statuses] =
|
|
statuses - domain_statuses_attrs(frame.css('rem'), 'rem') + domain_statuses_attrs(frame.css('add'), 'add')
|
|
|
|
if errors.empty? && verify
|
|
self.upid = current_user.registrar.id if current_user.registrar
|
|
self.up_date = Time.zone.now
|
|
end
|
|
|
|
registrant_verification_needed = false
|
|
# registrant block may not be present, so we need this to rule out false positives
|
|
if frame.css('registrant').text.present?
|
|
registrant_verification_needed = verification_needed?(code: frame.css('registrant').text)
|
|
end
|
|
|
|
if registrant_verification_needed && disputed?
|
|
disputed_pw = frame.css('reserved > pw').text
|
|
if disputed_pw.blank?
|
|
add_epp_error('2304', nil, nil, 'Required parameter missing; reserved' \
|
|
'pw element required for dispute domains')
|
|
else
|
|
dispute = Dispute.active.find_by(domain_name: name, password: disputed_pw)
|
|
if dispute
|
|
Dispute.close_by_domain(name)
|
|
registrant_verification_needed = false # Prevent asking current registrant confirmation
|
|
else
|
|
add_epp_error('2202', nil, nil, 'Invalid authorization information; '\
|
|
'invalid reserved>pw value')
|
|
end
|
|
end
|
|
end
|
|
|
|
unverified_registrant_params = frame.css('registrant').present? &&
|
|
frame.css('registrant').attr('verified').to_s.downcase != 'yes'
|
|
|
|
if registrant_verification_needed && errors.empty? && verify &&
|
|
Setting.request_confirmation_on_registrant_change_enabled &&
|
|
unverified_registrant_params
|
|
registrant_verification_asked!(frame.to_s, current_user.id) unless disputed?
|
|
end
|
|
|
|
errors.empty? && super(at)
|
|
end
|
|
|
|
def apply_pending_delete!
|
|
preclean_pendings
|
|
statuses.delete(DomainStatus::PENDING_DELETE_CONFIRMATION)
|
|
statuses.delete(DomainStatus::PENDING_DELETE)
|
|
DomainDeleteMailer.accepted(self).deliver_now
|
|
clean_pendings!
|
|
set_pending_delete!
|
|
true
|
|
end
|
|
|
|
def attach_legal_document(legal_document_data)
|
|
return unless legal_document_data
|
|
return unless legal_document_data[:body]
|
|
return if legal_document_data[:body].starts_with?(ENV['legal_documents_dir'])
|
|
|
|
legal_documents.create(
|
|
document_type: legal_document_data[:type],
|
|
body: legal_document_data[:body]
|
|
)
|
|
end
|
|
|
|
def epp_destroy(frame, user_id)
|
|
if discarded?
|
|
add_epp_error('2304', nil, nil, 'Object status prohibits operation')
|
|
return
|
|
end
|
|
|
|
if doc = attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call)
|
|
frame.css("legalDocument").first.content = doc.path if doc&.persisted?
|
|
end
|
|
|
|
if Setting.request_confirmation_on_domain_deletion_enabled &&
|
|
frame.css('delete').children.css('delete').attr('verified').to_s.downcase != 'yes'
|
|
|
|
registrant_verification_asked!(frame.to_s, user_id)
|
|
pending_delete!
|
|
manage_automatic_statuses
|
|
true # aka 1001 pending_delete
|
|
else
|
|
set_pending_delete!
|
|
end
|
|
end
|
|
|
|
def set_pending_delete!
|
|
unless pending_deletable?
|
|
add_epp_error('2304', nil, nil, I18n.t(:object_status_prohibits_operation))
|
|
return
|
|
end
|
|
|
|
self.delete_date = Time.zone.today + Setting.redemption_grace_period.days + 1.day
|
|
set_pending_delete
|
|
set_server_hold if server_holdable?
|
|
save(validate: false)
|
|
end
|
|
|
|
### RENEW ###
|
|
|
|
def renew(cur_exp_date, period, unit = 'y')
|
|
@is_renewal = true
|
|
validate_exp_dates(cur_exp_date)
|
|
|
|
add_renew_epp_errors unless renewable?
|
|
|
|
return false if errors.any?
|
|
|
|
period = period.to_i
|
|
plural_period_unit_name = (unit == 'm' ? 'months' : 'years').to_sym
|
|
renewed_expire_time = valid_to.advance(plural_period_unit_name => period.to_i)
|
|
|
|
max_reg_time = 11.years.from_now
|
|
|
|
if renewed_expire_time >= max_reg_time
|
|
add_epp_error('2105', nil, nil, I18n.t('epp.domains.object_is_not_eligible_for_renewal',
|
|
max_date: max_reg_time.to_date.to_s(:db)))
|
|
return false if errors.any?
|
|
end
|
|
|
|
self.expire_time = renewed_expire_time
|
|
self.outzone_at = nil
|
|
self.delete_date = nil
|
|
self.period = period
|
|
self.period_unit = unit
|
|
|
|
statuses.delete(DomainStatus::SERVER_HOLD)
|
|
statuses.delete(DomainStatus::EXPIRED)
|
|
cancel_pending_delete
|
|
|
|
save
|
|
end
|
|
|
|
def add_renew_epp_errors
|
|
if renew_blocking_statuses.any? && !renewable?
|
|
add_epp_error('2304', 'status', renew_blocking_statuses,
|
|
I18n.t('object_status_prohibits_operation'))
|
|
end
|
|
end
|
|
|
|
### TRANSFER ###
|
|
|
|
def transfer(frame, action, current_user)
|
|
if discarded?
|
|
add_epp_error('2106', nil, nil, 'Object is not eligible for transfer')
|
|
return
|
|
end
|
|
|
|
@is_transfer = true
|
|
|
|
case action
|
|
when 'query'
|
|
return transfers.last if transfers.any?
|
|
when 'request'
|
|
return pending_transfer if pending_transfer
|
|
return query_transfer(frame, current_user)
|
|
when 'approve'
|
|
return approve_transfer(frame, current_user) if pending_transfer
|
|
when 'reject'
|
|
return reject_transfer(frame, current_user) if pending_transfer
|
|
end
|
|
end
|
|
|
|
def query_transfer(frame, current_user)
|
|
if current_user.registrar == registrar
|
|
add_epp_error('2002', nil, nil, I18n.t(:domain_already_belongs_to_the_querying_registrar))
|
|
return
|
|
end
|
|
|
|
transaction do
|
|
dt = transfers.create!(
|
|
transfer_requested_at: Time.zone.now,
|
|
old_registrar: registrar,
|
|
new_registrar: current_user.registrar
|
|
)
|
|
|
|
if dt.pending?
|
|
registrar.notifications.create!(
|
|
text: I18n.t('transfer_requested'),
|
|
attached_obj_id: dt.id,
|
|
attached_obj_type: dt.class.to_s
|
|
)
|
|
end
|
|
|
|
if dt.approved?
|
|
dt.send(:notify_old_registrar)
|
|
transfer_contacts(current_user.registrar)
|
|
regenerate_transfer_code
|
|
self.registrar = current_user.registrar
|
|
end
|
|
|
|
attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call)
|
|
save!(validate: false)
|
|
|
|
return dt
|
|
end
|
|
end
|
|
|
|
def approve_transfer(frame, current_user)
|
|
pt = pending_transfer
|
|
|
|
if current_user.registrar != pt.old_registrar
|
|
add_epp_error('2304', nil, nil, I18n.t('transfer_can_be_approved_only_by_current_registrar'))
|
|
return
|
|
end
|
|
|
|
transaction do
|
|
pt.update!(
|
|
status: DomainTransfer::CLIENT_APPROVED,
|
|
transferred_at: Time.zone.now
|
|
)
|
|
|
|
transfer_contacts(pt.new_registrar)
|
|
regenerate_transfer_code
|
|
self.registrar = pt.new_registrar
|
|
|
|
attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call)
|
|
save!(validate: false)
|
|
end
|
|
|
|
pt
|
|
end
|
|
|
|
def reject_transfer(frame, current_user)
|
|
pt = pending_transfer
|
|
|
|
if current_user.registrar != pt.old_registrar
|
|
add_epp_error('2304', nil, nil, I18n.t('transfer_can_be_rejected_only_by_current_registrar'))
|
|
return
|
|
end
|
|
|
|
transaction do
|
|
pt.update!(
|
|
status: DomainTransfer::CLIENT_REJECTED
|
|
)
|
|
|
|
attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call)
|
|
save!(validate: false)
|
|
end
|
|
|
|
pt
|
|
end
|
|
|
|
def validate_exp_dates(cur_exp_date)
|
|
begin
|
|
return if cur_exp_date.to_date == valid_to.to_date
|
|
rescue
|
|
add_epp_error('2306', 'curExpDate', cur_exp_date, I18n.t('errors.messages.epp_exp_dates_do_not_match'))
|
|
return
|
|
end
|
|
add_epp_error('2306', 'curExpDate', cur_exp_date, I18n.t('errors.messages.epp_exp_dates_do_not_match'))
|
|
end
|
|
|
|
### ABILITIES ###
|
|
|
|
|
|
def can_be_deleted?
|
|
if disputed?
|
|
errors.add(:base, :domain_status_prohibits_operation)
|
|
return false
|
|
end
|
|
|
|
begin
|
|
errors.add(:base, :domain_status_prohibits_operation)
|
|
return false
|
|
end if (statuses & [DomainStatus::CLIENT_DELETE_PROHIBITED, DomainStatus::SERVER_DELETE_PROHIBITED]).any?
|
|
|
|
true
|
|
end
|
|
|
|
## SHARED
|
|
|
|
# For domain transfer
|
|
def authenticate(pw)
|
|
errors.add(:transfer_code, :wrong_pw) if pw != transfer_code
|
|
errors.empty?
|
|
end
|
|
|
|
class << self
|
|
def parse_period_unit_from_frame(parsed_frame)
|
|
p = parsed_frame.css('period').first
|
|
return nil unless p
|
|
p[:unit]
|
|
end
|
|
|
|
def check_availability(domain_names)
|
|
domain_names = [domain_names] if domain_names.is_a?(String)
|
|
|
|
result = []
|
|
|
|
domain_names.each do |domain_name_as_string|
|
|
domain_name_as_string.strip!
|
|
domain_name_as_string.downcase!
|
|
|
|
unless DomainNameValidator.validate_format(domain_name_as_string)
|
|
result << { name: domain_name_as_string, avail: 0, reason: 'invalid format' }
|
|
next
|
|
end
|
|
|
|
domain_name = DNS::DomainName.new(SimpleIDN.to_unicode(domain_name_as_string))
|
|
|
|
if domain_name.unavailable?
|
|
reason = I18n.t("errors.messages.epp_domain_#{domain_name.unavailability_reason}")
|
|
result << { name: domain_name_as_string, avail: 0, reason: reason }
|
|
next
|
|
end
|
|
|
|
result << { name: domain_name_as_string, avail: 1 }
|
|
end
|
|
|
|
result
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def verification_needed?(code:)
|
|
new_registrant = Registrant.find_by(code: code)
|
|
return false if new_registrant.try(:identical_to?, registrant)
|
|
|
|
registrant.code != code
|
|
end
|
|
end
|