Merge remote-tracking branch 'origin/master' into registrant-api-fetch-improvements

This commit is contained in:
Karl Erik Õunapuu 2020-11-30 10:34:28 +02:00
commit 3761fe7bbd
No known key found for this signature in database
GPG key ID: C9DD647298A34764
97 changed files with 2824 additions and 821 deletions

View file

@ -1,16 +0,0 @@
module Repp
class AccountV1 < Grape::API
version 'v1', using: :path
resource :accounts do
desc 'Return current cash account balance'
get 'balance' do
@response = {
balance: current_user.registrar.cash_account.balance,
currency: current_user.registrar.cash_account.currency
}
end
end
end
end

View file

@ -1,65 +0,0 @@
module Repp
class API < Grape::API
format :json
prefix :repp
http_basic do |username, password|
@current_user ||= ApiUser.find_by(username: username, plain_text_password: password)
if @current_user
true
else
error! I18n.t('api_user_not_found'), 401
end
end
before do
webclient_request = ENV['webclient_ips'].split(',').map(&:strip).include?(request.ip)
unless webclient_request
error! I18n.t('api.authorization.ip_not_allowed', ip: request.ip), 401 unless @current_user.registrar.api_ip_white?(request.ip)
end
if @current_user.cannot?(:view, :repp)
error! I18n.t('no_permission'), 401 unless @current_user.registrar.api_ip_white?(request.ip)
end
next if Rails.env.test? || Rails.env.development?
message = 'Certificate mismatch! Cert common name should be:'
request_name = env['HTTP_SSL_CLIENT_S_DN_CN']
if webclient_request
webclient_cert_name = ENV['webclient_cert_common_name'] || 'webclient'
error! "Webclient #{message} #{webclient_cert_name}", 401 if webclient_cert_name != request_name
else
unless @current_user.pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'],
request.env['HTTP_SSL_CLIENT_S_DN_CN'])
error! "#{message} #{@current_user.username}", 401
end
end
end
helpers do
attr_reader :current_user
end
after do
ApiLog::ReppLog.create({
request_path: request.path,
request_method: request.request_method,
request_params: request.params.except('route_info').to_json,
response: @response.to_json,
response_code: status,
api_user_name: current_user.try(:username),
api_user_registrar: current_user.try(:registrar).try(:to_s),
ip: request.ip,
uuid: request.try(:uuid)
})
end
mount Repp::DomainV1
mount Repp::ContactV1
mount Repp::AccountV1
mount Repp::DomainTransfersV1
mount Repp::NameserversV1
mount Repp::DomainContactsV1
end
end

View file

@ -1,35 +0,0 @@
module Repp
class ContactV1 < Grape::API
version 'v1', using: :path
resource :contacts do
desc 'Return list of contact'
params do
optional :limit, type: Integer, values: (1..200).to_a, desc: 'How many contacts to show'
optional :offset, type: Integer, desc: 'Contact number to start at'
optional :details, type: String, values: %w(true false), desc: 'Whether to include details'
end
get '/' do
limit = params[:limit] || 200
offset = params[:offset] || 0
if params[:details] == 'true'
contacts = current_user.registrar.contacts.limit(limit).offset(offset)
unless Contact.address_processing?
attributes = Contact.attribute_names - Contact.address_attribute_names
contacts = contacts.select(attributes)
end
else
contacts = current_user.registrar.contacts.limit(limit).offset(offset).pluck(:code)
end
@response = {
contacts: contacts,
total_number_of_records: current_user.registrar.contacts.count
}
end
end
end
end

View file

@ -1,47 +0,0 @@
module Repp
class DomainContactsV1 < Grape::API
version 'v1', using: :path
resource :domains do
resource :contacts do
patch '/' do
current_contact = current_user.registrar.contacts
.find_by(code: params[:current_contact_id])
new_contact = current_user.registrar.contacts.find_by(code: params[:new_contact_id])
unless current_contact
error!({ error: { type: 'invalid_request_error',
param: 'current_contact_id',
message: "No such contact: #{params[:current_contact_id]}"} },
:bad_request)
end
unless new_contact
error!({ error: { type: 'invalid_request_error',
param: 'new_contact_id',
message: "No such contact: #{params[:new_contact_id]}" } },
:bad_request)
end
if new_contact.invalid?
error!({ error: { type: 'invalid_request_error',
param: 'new_contact_id',
message: 'New contact must be valid' } },
:bad_request)
end
if current_contact == new_contact
error!({ error: { type: 'invalid_request_error',
message: 'New contact ID must be different from current' \
' contact ID' } },
:bad_request)
end
affected_domains, skipped_domains = TechDomainContact
.replace(current_contact, new_contact)
@response = { affected_domains: affected_domains, skipped_domains: skipped_domains }
end
end
end
end
end

View file

@ -1,48 +0,0 @@
module Repp
class DomainTransfersV1 < Grape::API
version 'v1', using: :path
resource :domain_transfers do
post '/' do
params do
requires :data, type: Hash do
requires :domainTransfers, type: Array do
requires :domainName, type: String, allow_blank: false
requires :transferCode, type: String, allow_blank: false
end
end
end
new_registrar = current_user.registrar
domain_transfers = params['data']['domainTransfers']
successful_domain_transfers = []
errors = []
domain_transfers.each do |domain_transfer|
domain_name = domain_transfer['domainName']
transfer_code = domain_transfer['transferCode']
domain = Domain.find_by(name: domain_name)
if domain
if domain.transfer_code == transfer_code
DomainTransfer.request(domain, new_registrar)
successful_domain_transfers << { type: 'domain_transfer', attributes: { domain_name: domain.name } }
else
errors << { title: "#{domain_name} transfer code is wrong" }
end
else
errors << { title: "#{domain_name} does not exist" }
end
end
if errors.none?
status 200
@response = { data: successful_domain_transfers }
else
status 400
@response = { errors: errors }
end
end
end
end
end

View file

@ -1,50 +0,0 @@
module Repp
class DomainV1 < Grape::API
version 'v1', using: :path
resource :domains do
desc 'Return list of domains'
params do
optional :limit, type: Integer, values: (1..200).to_a, desc: 'How many domains to show'
optional :offset, type: Integer, desc: 'Domain number to start at'
optional :details, type: String, values: %w(true false), desc: 'Whether to include details'
end
get '/' do
limit = params[:limit] || 200
offset = params[:offset] || 0
if params[:details] == 'true'
domains = current_user.registrar.domains.limit(limit).offset(offset)
else
domains = current_user.registrar.domains.limit(limit).offset(offset).pluck(:name)
end
@response = {
domains: domains,
total_number_of_records: current_user.registrar.domains.count
}
end
# example: curl -u registrar1:password localhost:3000/repp/v1/domains/1/transfer_info -H "Auth-Code: authinfopw1"
get '/:id/transfer_info', requirements: { id: /.*/ } do
ident = params[:id]
domain = ident.match?(/\A[0-9]+\z/) ? Domain.find_by(id: ident) : Domain.find_by_idn(ident)
error! I18n.t('errors.messages.epp_domain_not_found'), 404 unless domain
error! I18n.t('errors.messages.epp_authorization_error'), 401 unless domain.transfer_code.eql? request.headers['Auth-Code']
contact_repp_json = proc{|contact|
contact.as_json.slice("code", "name", "ident", "ident_type", "ident_country_code", "phone", "email", "street", "city", "zip","country_code", "statuses")
}
@response = {
domain: domain.name,
registrant: contact_repp_json.call(domain.registrant),
admin_contacts: domain.admin_contacts.map{|e| contact_repp_json.call(e)},
tech_contacts: domain.tech_contacts.map{|e| contact_repp_json.call(e)}
}
end
end
end
end

View file

@ -1,49 +0,0 @@
module Repp
class NameserversV1 < Grape::API
version 'v1', using: :path
resource 'registrar/nameservers' do
put '/' do
params do
requires :data, type: Hash, allow_blank: false do
requires :type, type: String, allow_blank: false
requires :id, type: String, allow_blank: false
optional :domains, type: Array
requires :attributes, type: Hash, allow_blank: false do
requires :hostname, type: String, allow_blank: false
requires :ipv4, type: Array
requires :ipv6, type: Array
end
end
end
hostname = params[:data][:id]
unless current_user.registrar.nameservers.exists?(hostname: hostname)
error!({ errors: [{ title: "Hostname #{hostname} does not exist" }] }, 404)
end
new_attributes = {
hostname: params[:data][:attributes][:hostname],
ipv4: params[:data][:attributes][:ipv4],
ipv6: params[:data][:attributes][:ipv6],
}
domains = params[:data][:domains] || []
begin
affected_domains = current_user.registrar.replace_nameservers(hostname, new_attributes,
domains: domains)
rescue ActiveRecord::RecordInvalid => e
error!({ errors: e.record.errors.full_messages.map { |error| { title: error } } }, 400)
end
status 200
@response = { data: { type: 'nameserver',
id: params[:data][:attributes][:hostname],
attributes: params[:data][:attributes] },
affected_domains: affected_domains }
end
end
end
end

View file

@ -4,26 +4,15 @@ module Admin
def create
authorize! :manage, domain
notice = t('.scheduled')
domain.transaction do
domain.schedule_force_delete(type: force_delete_type)
domain.registrar.notifications.create!(text: t('force_delete_set_on_domain',
domain_name: domain.name,
outzone_date: domain.outzone_date,
purge_date: domain.purge_date))
notify_by_email if notify_by_email?
result = domain.schedule_force_delete(type: force_delete_type,
notify_by_email: notify_by_email?)
notice = result.errors.messages[:domain].first unless result.valid?
end
redirect_to edit_admin_domain_url(domain), notice: t('.scheduled')
end
def notify_by_email
if force_delete_type == :fast_track
send_email
domain.update(contact_notification_sent_date: Time.zone.today)
else
domain.update(template_name: domain.notification_template)
end
redirect_to edit_admin_domain_url(domain), notice: notice
end
def destroy
@ -42,13 +31,6 @@ module Admin
ActiveRecord::Type::Boolean.new.cast(params[:notify_by_email])
end
def send_email
DomainDeleteMailer.forced(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant,
template_name: domain.notification_template).deliver_now
end
def force_delete_type
soft_delete? ? :soft : :fast_track
end

View file

@ -0,0 +1,119 @@
require 'serializers/registrant_api/domain'
module Api
module V1
module Registrant
class ConfirmsController < ::Api::V1::Registrant::BaseController
skip_before_action :authenticate, :set_paper_trail_whodunnit
before_action :set_domain, only: %i[index update]
before_action :verify_action, only: %i[index update]
before_action :verify_decision, only: %i[update]
def index
res = {
domain_name: @domain.name,
current_registrant: serialized_registrant(@domain.registrant),
}
unless delete_action?
res[:new_registrant] = serialized_registrant(@domain.pending_registrant)
end
render json: res, status: :ok
end
def update
verification = RegistrantVerification.new(domain_id: @domain.id,
verification_token: verify_params[:token])
unless delete_action? ? delete_action(verification) : change_action(verification)
head :bad_request
return
end
render json: { domain_name: @domain.name,
current_registrant: serialized_registrant(current_registrant),
status: params[:decision] }, status: :ok
end
private
def initiator
"email link, #{I18n.t(:user_not_authenticated)}"
end
def current_registrant
confirmed? && !delete_action? ? @domain.pending_registrant : @domain.registrant
end
def confirmed?
verify_params[:decision] == 'confirmed'
end
def change_action(verification)
if confirmed?
verification.domain_registrant_change_confirm!(initiator)
else
verification.domain_registrant_change_reject!(initiator)
end
end
def delete_action(verification)
if confirmed?
verification.domain_registrant_delete_confirm!(initiator)
else
verification.domain_registrant_delete_reject!(initiator)
end
end
def serialized_registrant(registrant)
{
name: registrant.try(:name),
ident: registrant.try(:ident),
country: registrant.try(:ident_country_code),
}
end
def verify_params
params do |p|
p.require(:name)
p.require(:token)
p.permit(:decision)
end
end
def delete_action?
return true if params[:template] == 'delete'
false
end
def verify_decision
return if %w[confirmed rejected].include?(params[:decision])
head :not_found
end
def set_domain
@domain = Domain.find_by(name: verify_params[:name])
@domain ||= Domain.find_by(name_puny: verify_params[:name])
return if @domain
render json: { error: 'Domain not found' }, status: :not_found
end
def verify_action
action = if params[:template] == 'change'
@domain.registrant_update_confirmable?(verify_params[:token])
elsif params[:template] == 'delete'
@domain.registrant_delete_confirmable?(verify_params[:token])
end
return if action
render json: { error: 'Application expired or not found' }, status: :unauthorized
end
end
end
end
end

View file

@ -1,10 +1,9 @@
require 'deserializers/xml/contact_update'
require 'deserializers/xml/contact_create'
module Epp
class ContactsController < BaseController
before_action :find_contact, only: [:info, :update, :delete]
before_action :find_password, only: [:info, :update, :delete]
helper_method :address_processing?
def info
authorize! :info, @contact, @password
@ -21,25 +20,13 @@ module Epp
def create
authorize! :create, Epp::Contact
frame = params[:parsed_frame]
@contact = Epp::Contact.new(frame, current_user.registrar)
@contact.add_legal_file_to_new(frame)
@contact.generate_code
@contact = Epp::Contact.new(params[:parsed_frame], current_user.registrar)
collected_data = ::Deserializers::Xml::ContactCreate.new(params[:parsed_frame])
action = Actions::ContactCreate.new(@contact, collected_data.legal_document,
collected_data.ident)
if @contact.save
if !address_processing? && address_given?
@response_code = 1100
@response_description = t('epp.contacts.completed_without_address')
else
@response_code = 1000
@response_description = t('epp.contacts.completed')
end
render_epp_response '/epp/contacts/save'
else
handle_errors(@contact)
end
action_call_response(action: action)
end
def update
@ -52,29 +39,18 @@ module Epp
collected_data.ident,
current_user)
if action.call
if !address_processing? && address_given?
@response_code = 1100
@response_description = t('epp.contacts.completed_without_address')
else
@response_code = 1000
@response_description = t('epp.contacts.completed')
end
render_epp_response 'epp/contacts/save'
else
handle_errors(@contact)
end
action_call_response(action: action)
end
def delete
authorize! :delete, @contact, @password
if @contact.destroy_and_clean(params[:parsed_frame])
render_epp_response '/epp/contacts/delete'
else
action = Actions::ContactDelete.new(@contact, params[:legal_document])
unless action.call
handle_errors(@contact)
return
end
render_epp_response '/epp/contacts/delete'
end
def renew
@ -91,6 +67,26 @@ module Epp
private
def opt_addr?
!Contact.address_processing? && address_given?
end
def action_call_response(action:)
# rubocop:disable Style/AndOr
(handle_errors(@contact) and return) unless action.call
# rubocop:enable Style/AndOr
if opt_addr?
@response_code = 1100
@response_description = t('epp.contacts.completed_without_address')
else
@response_code = 1000
@response_description = t('epp.contacts.completed')
end
render_epp_response('epp/contacts/save')
end
def find_password
@password = params[:parsed_frame].css('authInfo pw').text
end
@ -129,8 +125,7 @@ module Epp
'postalInfo > addr > cc',
]
required_attributes.concat(address_attributes) if address_processing?
required_attributes.concat(address_attributes) if Contact.address_processing?
requires(*required_attributes)
ident = params[:parsed_frame].css('ident')
@ -206,9 +201,5 @@ module Epp
def address_given?
params[:parsed_frame].css('postalInfo addr').size != 0
end
def address_processing?
Contact.address_processing?
end
end
end

View file

@ -15,12 +15,12 @@ class Registrar
csv.each do |row|
domain_name = row['Domain']
transfer_code = row['Transfer code']
domain_transfers << { 'domainName' => domain_name, 'transferCode' => transfer_code }
domain_transfers << { 'domain_name' => domain_name, 'transfer_code' => transfer_code }
end
uri = URI.parse("#{ENV['repp_url']}domain_transfers")
uri = URI.parse("#{ENV['repp_url']}domains/transfer")
request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
request.body = { data: { domainTransfers: domain_transfers } }.to_json
request.body = { data: { domain_transfers: domain_transfers } }.to_json
request.basic_auth(current_registrar_user.username,
current_registrar_user.plain_text_password)

View file

@ -0,0 +1,11 @@
module Repp
module V1
class AccountsController < BaseController
def balance
resp = { balance: current_user.registrar.cash_account.balance,
currency: current_user.registrar.cash_account.currency }
render_success(data: resp)
end
end
end
end

View file

@ -3,9 +3,9 @@ module Repp
class AuctionsController < ActionController::API
def index
auctions = Auction.started
@response = { count: auctions.count, auctions: auctions_to_json(auctions) }
render json: { count: auctions.count,
auctions: auctions_to_json(auctions) }
render json: @response
end
private

View file

@ -0,0 +1,111 @@
module Repp
module V1
class BaseController < ActionController::API
rescue_from ActiveRecord::RecordNotFound, with: :not_found_error
before_action :authenticate_user
before_action :check_ip_restriction
attr_reader :current_user
before_action :set_paper_trail_whodunnit
rescue_from ActionController::ParameterMissing do |exception|
render json: { code: 2003, message: exception }, status: :bad_request
end
after_action do
ApiLog::ReppLog.create(
request_path: request.path, request_method: request.request_method,
request_params: request.params.except('route_info').to_json, uuid: request.try(:uuid),
response: @response.to_json, response_code: status, ip: request.ip,
api_user_name: current_user.try(:username),
api_user_registrar: current_user.try(:registrar).try(:to_s)
)
end
private
def set_paper_trail_whodunnit
::PaperTrail.request.whodunnit = current_user
end
def render_success(code: nil, message: nil, data: nil)
@response = { code: code || 1000, message: message || 'Command completed successfully',
data: data || {} }
render(json: @response, status: :ok)
end
def epp_errors
@epp_errors ||= []
end
def handle_errors(obj = nil, update: false)
@epp_errors ||= []
obj&.construct_epp_errors
@epp_errors += obj.errors[:epp_errors] if obj
format_epp_errors if update
@epp_errors.uniq!
render_epp_error
end
def format_epp_errors
@epp_errors.each_with_index do |error, index|
blocked_by_delete_prohibited?(error, index)
end
end
def blocked_by_delete_prohibited?(error, index)
if error[:code] == 2304 && error[:value][:val] == DomainStatus::SERVER_DELETE_PROHIBITED &&
error[:value][:obj] == 'status'
@epp_errors[index][:value][:val] = DomainStatus::PENDING_UPDATE
end
end
def render_epp_error(status = :bad_request, data = {})
@epp_errors ||= []
@epp_errors << { code: 2304, msg: 'Command failed' } if data != {}
@response = { code: @epp_errors[0][:code].to_i, message: @epp_errors[0][:msg], data: data }
render(json: @response, status: status)
end
def basic_token
pattern = /^Basic /
header = request.headers['Authorization']
header = header.gsub(pattern, '') if header&.match(pattern)
header.strip
end
def authenticate_user
username, password = Base64.urlsafe_decode64(basic_token).split(':')
@current_user ||= ApiUser.find_by(username: username, plain_text_password: password)
return if @current_user
raise(ArgumentError)
rescue NoMethodError, ArgumentError
@response = { code: 2202, message: 'Invalid authorization information' }
render(json: @response, status: :unauthorized)
end
def check_ip_restriction
allowed = @current_user.registrar.api_ip_white?(request.ip)
return if allowed
@response = { code: 2202,
message: I18n.t('registrar.authorization.ip_not_allowed', ip: request.ip) }
render(json: @response, status: :unauthorized)
end
def not_found_error
@response = { code: 2303, message: 'Object does not exist' }
render(json: @response, status: :not_found)
end
end
end
end

View file

@ -0,0 +1,137 @@
require 'serializers/repp/contact'
module Repp
module V1
class ContactsController < BaseController
before_action :find_contact, only: %i[show update destroy]
## GET /repp/v1/contacts
def index
record_count = current_user.registrar.contacts.count
contacts = showable_contacts(params[:details], params[:limit] || 200,
params[:offset] || 0)
@response = { contacts: contacts, total_number_of_records: record_count }
render(json: @response, status: :ok)
end
## GET /repp/v1/contacts/1
def show
serializer = ::Serializers::Repp::Contact.new(@contact,
show_address: Contact.address_processing?)
render_success(data: serializer.to_json)
end
## GET /repp/v1/contacts/check/1
def check
contact = Epp::Contact.find_by(code: params[:id])
data = { contact: { id: params[:id], available: contact.nil? } }
render_success(data: data)
end
## POST /repp/v1/contacts
def create
@contact = Epp::Contact.new(contact_params_with_address, current_user.registrar, epp: false)
action = Actions::ContactCreate.new(@contact, params[:legal_document],
contact_ident_params)
unless action.call
handle_errors(@contact)
return
end
render_success(create_update_success_body)
end
## PUT /repp/v1/contacts/1
def update
action = Actions::ContactUpdate.new(@contact, contact_params_with_address(required: false),
params[:legal_document],
contact_ident_params(required: false), current_user)
unless action.call
handle_errors(@contact)
return
end
render_success(create_update_success_body)
end
def destroy
action = Actions::ContactDelete.new(@contact, params[:legal_document])
unless action.call
handle_errors(@contact)
return
end
render_success
end
def contact_addr_present?
return false unless contact_addr_params.key?(:addr)
contact_addr_params[:addr].keys.any?
end
def create_update_success_body
{ code: opt_addr? ? 1100 : nil, data: { contact: { id: @contact.code } },
message: opt_addr? ? I18n.t('epp.contacts.completed_without_address') : nil }
end
def showable_contacts(details, limit, offset)
contacts = current_user.registrar.contacts.limit(limit).offset(offset)
return contacts.pluck(:code) unless details
contacts = contacts.map do |contact|
serializer = ::Serializers::Repp::Contact.new(contact,
show_address: Contact.address_processing?)
serializer.to_json
end
contacts
end
def opt_addr?
!Contact.address_processing? && contact_addr_present?
end
def find_contact
code = params[:id]
@contact = Epp::Contact.find_by!(code: code, registrar: current_user.registrar)
end
def contact_params_with_address(required: true)
return contact_create_params(required: required) unless contact_addr_params.key?(:addr)
addr = {}
contact_addr_params[:addr].each_key { |k| addr[k] = contact_addr_params[:addr][k] }
contact_create_params(required: required).merge(addr)
end
def contact_create_params(required: true)
params.require(:contact).require(%i[name email phone]) if required
params.require(:contact).permit(:name, :email, :phone, :id)
end
def contact_ident_params(required: true)
if required
params.require(:contact).require(:ident).require(%i[ident ident_type ident_country_code])
params.require(:contact).require(:ident).permit(:ident, :ident_type, :ident_country_code)
else
params.permit(contact: { ident: %i[ident ident_type ident_country_code] })
end
params[:contact][:ident]
end
def contact_addr_params
if Contact.address_processing?
params.require(:contact).require(:addr).require(%i[country_code city street zip])
params.require(:contact).require(:addr).permit(:country_code, :city, :street, :zip)
else
params.require(:contact).permit(addr: %i[country_code city street zip])
end
end
end
end
end

View file

@ -0,0 +1,42 @@
module Repp
module V1
module Domains
class ContactsController < BaseController
before_action :set_current_contact, only: [:update]
before_action :set_new_contact, only: [:update]
def set_current_contact
@current_contact = current_user.registrar.contacts.find_by!(
code: contact_params[:current_contact_id]
)
end
def set_new_contact
@new_contact = current_user.registrar.contacts.find_by!(code: params[:new_contact_id])
end
def update
@epp_errors ||= []
@epp_errors << { code: 2304, msg: 'New contact must be valid' } if @new_contact.invalid?
if @new_contact == @current_contact
@epp_errors << { code: 2304, msg: 'New contact must be different from current' }
end
return handle_errors if @epp_errors.any?
affected, skipped = TechDomainContact.replace(@current_contact, @new_contact)
@response = { affected_domains: affected, skipped_domains: skipped }
render_success(data: @response)
end
private
def contact_params
params.require(%i[current_contact_id new_contact_id])
params.permit(:current_contact_id, :new_contact_id)
end
end
end
end
end

View file

@ -0,0 +1,94 @@
module Repp
module V1
class DomainsController < BaseController
before_action :set_authorized_domain, only: [:transfer_info]
def index
records = current_user.registrar.domains
domains = records.limit(limit).offset(offset)
domains = domains.pluck(:name) unless index_params[:details] == 'true'
render_success(data: { domains: domains, total_number_of_records: records.count })
end
def transfer_info
contact_fields = %i[code name ident ident_type ident_country_code phone email street city
zip country_code statuses]
data = {
domain: @domain.name,
registrant: @domain.registrant.as_json(only: contact_fields),
admin_contacts: @domain.admin_contacts.map { |c| c.as_json(only: contact_fields) },
tech_contacts: @domain.tech_contacts.map { |c| c.as_json(only: contact_fields) },
}
render_success(data: data)
end
def transfer
@errors ||= []
@successful = []
transfer_params[:domain_transfers].each do |transfer|
initiate_transfer(transfer)
end
render_success(data: { success: @successful, failed: @errors })
end
def initiate_transfer(transfer)
domain = Epp::Domain.find_or_initialize_by(name: transfer[:domain_name])
action = Actions::DomainTransfer.new(domain, transfer[:transfer_code],
current_user.registrar)
if action.call
@successful << { type: 'domain_transfer', domain_name: domain.name }
else
@errors << { type: 'domain_transfer', domain_name: domain.name,
errors: domain.errors[:epp_errors] }
end
end
private
def transfer_params
params.require(:data).require(:domain_transfers).each do |t|
t.require(:domain_name)
t.permit(:domain_name)
t.require(:transfer_code)
t.permit(:transfer_code)
end
params.require(:data).permit(domain_transfers: %i[domain_name transfer_code])
end
def transfer_info_params
params.require(:id)
params.permit(:id)
end
def set_authorized_domain
@epp_errors ||= []
h = {}
h[transfer_info_params[:id].match?(/\A[0-9]+\z/) ? :id : :name] = transfer_info_params[:id]
@domain = Domain.find_by!(h)
return if @domain.transfer_code.eql?(request.headers['Auth-Code'])
@epp_errors << { code: 2202, msg: I18n.t('errors.messages.epp_authorization_error') }
handle_errors
end
def limit
index_params[:limit] || 200
end
def offset
index_params[:offset] || 0
end
def index_params
params.permit(:limit, :offset, :details)
end
end
end
end

View file

@ -0,0 +1,51 @@
module Repp
module V1
module Registrar
class NameserversController < BaseController
before_action :verify_nameserver_existance, only: %i[update]
def update
domains = params[:data][:domains] || []
affected = current_user.registrar
.replace_nameservers(hostname,
hostname_params[:data][:attributes],
domains: domains)
render_success(data: data_format_for_success(affected))
rescue ActiveRecord::RecordInvalid => e
handle_errors(e.record)
end
private
def data_format_for_success(affected_domains)
{
type: 'nameserver',
id: params[:data][:attributes][:hostname],
attributes: params[:data][:attributes],
affected_domains: affected_domains,
}
end
def hostname_params
params.require(:data).require(%i[type id])
params.require(:data).require(:attributes).require([:hostname])
params.permit(data: [
:type, :id,
{ domains: [],
attributes: [:hostname, { ipv4: [], ipv6: [] }] }
])
end
def hostname
hostname_params[:data][:id]
end
def verify_nameserver_existance
current_user.registrar.nameservers.find_by!(hostname: hostname)
end
end
end
end
end

View file

@ -3,8 +3,9 @@ module Repp
class RetainedDomainsController < ActionController::API
def index
domains = RetainedDomains.new(query_params)
@response = { count: domains.count, domains: domains.to_jsonable }
render json: { count: domains.count, domains: domains.to_jsonable }
render json: @response
end
def query_params

View file

@ -3,7 +3,7 @@ module ObjectVersionsHelper
version.object_changes.to_h.each do |key, value|
method_name = "#{key}=".to_sym
if new_object.respond_to?(method_name)
new_object.public_send(method_name, value.last)
new_object.public_send(method_name, event_value(version, value))
end
end
end
@ -12,4 +12,10 @@ module ObjectVersionsHelper
field_names = model.column_names
version.object.to_h.select { |key, _value| field_names.include?(key) }
end
private
def event_value(version, val)
version.event == 'destroy' ? val.first : val.last
end
end

View file

@ -0,0 +1,7 @@
module CancelForceDeleteInteraction
class Base < ActiveInteraction::Base
object :domain,
class: Domain,
description: 'Domain to cancel ForceDelete on'
end
end

View file

@ -0,0 +1,10 @@
module CancelForceDeleteInteraction
class CancelForceDelete < Base
def execute
compose(RemoveForceDeleteStatuses, inputs)
compose(RestoreStatusesBeforeForceDelete, inputs)
compose(ClearForceDeleteData, inputs)
compose(NotifyRegistrar, inputs)
end
end
end

View file

@ -0,0 +1,10 @@
module CancelForceDeleteInteraction
class ClearForceDeleteData < Base
def execute
domain.force_delete_data = nil
domain.force_delete_date = nil
domain.force_delete_start = nil
domain.save(validate: false)
end
end
end

View file

@ -0,0 +1,8 @@
module CancelForceDeleteInteraction
class NotifyRegistrar < Base
def execute
domain.registrar.notifications.create!(text: I18n.t('force_delete_cancelled',
domain_name: domain.name))
end
end
end

View file

@ -0,0 +1,11 @@
module CancelForceDeleteInteraction
class RemoveForceDeleteStatuses < Base
def execute
domain.statuses.delete(DomainStatus::FORCE_DELETE)
domain.statuses.delete(DomainStatus::SERVER_RENEW_PROHIBITED)
domain.statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED)
domain.statuses.delete(DomainStatus::CLIENT_HOLD)
domain.save(validate: false)
end
end
end

View file

@ -0,0 +1,9 @@
module CancelForceDeleteInteraction
class RestoreStatusesBeforeForceDelete < Base
def execute
domain.statuses = domain.statuses_before_force_delete
domain.statuses_before_force_delete = nil
domain.save(validate: false)
end
end
end

View file

@ -0,0 +1,22 @@
module DomainDeleteConfirmInteraction
class SendRequest < ActiveInteraction::Base
object :domain,
class: Domain,
description: 'Domain to send delete confirmation'
def execute
log
DomainDeleteMailer.confirmation_request(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant).deliver_later
end
private
def log
message = "Send DomainDeleteMailer#confirm email for domain #{domain.name} (##{domain.id})" \
" to #{domain.registrant.email}"
Rails.logger.info(message)
end
end
end

View file

@ -0,0 +1,16 @@
module ForceDeleteInteraction
class Base < ActiveInteraction::Base
object :domain,
class: Domain,
description: 'Domain to set ForceDelete on'
symbol :type,
default: :fast_track,
description: 'Force delete type, might be :fast_track or :soft'
boolean :notify_by_email,
default: false,
description: 'Do we need to send email notification'
validates :type, inclusion: { in: %i[fast_track soft] }
end
end

View file

@ -0,0 +1,11 @@
module ForceDeleteInteraction
class CheckDiscarded < Base
def execute
return true unless domain.discarded?
message = 'Force delete procedure cannot be scheduled while a domain is discarded'
errors.add(:domain, message)
end
end
end

View file

@ -0,0 +1,21 @@
module ForceDeleteInteraction
class NotifyByEmail < Base
def execute
return unless notify_by_email
if type == :fast_track
send_email
domain.update(contact_notification_sent_date: Time.zone.today)
else
domain.update(template_name: domain.notification_template)
end
end
def send_email
DomainDeleteMailer.forced(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant,
template_name: domain.notification_template).deliver_now
end
end
end

View file

@ -0,0 +1,10 @@
module ForceDeleteInteraction
class NotifyRegistrar < Base
def execute
domain.registrar.notifications.create!(text: I18n.t('force_delete_set_on_domain',
domain_name: domain.name,
outzone_date: domain.outzone_date,
purge_date: domain.purge_date))
end
end
end

View file

@ -0,0 +1,17 @@
module ForceDeleteInteraction
class PostSetProcess < Base
def execute
statuses = domain.statuses
# Stop all pending actions
statuses.delete(DomainStatus::PENDING_UPDATE)
statuses.delete(DomainStatus::PENDING_TRANSFER)
statuses.delete(DomainStatus::PENDING_RENEW)
statuses.delete(DomainStatus::PENDING_CREATE)
# Allow deletion
statuses.delete(DomainStatus::CLIENT_DELETE_PROHIBITED)
statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED)
domain.save(validate: false)
end
end
end

View file

@ -0,0 +1,13 @@
module ForceDeleteInteraction
class PrepareDomain < Base
STATUSES_TO_SET = [DomainStatus::FORCE_DELETE,
DomainStatus::SERVER_RENEW_PROHIBITED,
DomainStatus::SERVER_TRANSFER_PROHIBITED].freeze
def execute
domain.statuses_before_force_delete = domain.statuses
domain.statuses |= STATUSES_TO_SET
domain.save(validate: false)
end
end
end

View file

@ -0,0 +1,12 @@
module ForceDeleteInteraction
class SetForceDelete < Base
def execute
compose(CheckDiscarded, inputs)
compose(PrepareDomain, inputs)
compose(SetStatus, inputs)
compose(PostSetProcess, inputs)
compose(NotifyRegistrar, inputs)
compose(NotifyByEmail, inputs)
end
end
end

View file

@ -0,0 +1,38 @@
module ForceDeleteInteraction
class SetStatus < Base
def execute
domain.force_delete_type = type
type == :fast_track ? force_delete_fast_track : force_delete_soft
domain.save(validate: false)
end
def force_delete_fast_track
domain.force_delete_date = Time.zone.today +
expire_warning_period_days +
redemption_grace_period_days
domain.force_delete_start = Time.zone.today + 1.day
end
def force_delete_soft
years = (domain.valid_to.to_date - Time.zone.today).to_i / 365
soft_forcedelete_dates(years) if years.positive?
end
private
def soft_forcedelete_dates(years)
domain.force_delete_start = domain.valid_to - years.years
domain.force_delete_date = domain.force_delete_start +
Setting.expire_warning_period.days +
Setting.redemption_grace_period.days
end
def redemption_grace_period_days
Setting.redemption_grace_period.days + 1.day
end
def expire_warning_period_days
Setting.expire_warning_period.days
end
end
end

View file

@ -1,22 +0,0 @@
class DomainDeleteConfirmEmailJob < Que::Job
def run(domain_id)
domain = Domain.find(domain_id)
log(domain)
DomainDeleteMailer.confirmation_request(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant).deliver_now
end
private
def log(domain)
message = "Send DomainDeleteMailer#confirm email for domain #{domain.name} (##{domain.id})" \
" to #{domain.registrant.email}"
logger.info(message)
end
def logger
Rails.logger
end
end

View file

@ -1,4 +1,15 @@
class ApplicationMailer < ActionMailer::Base
append_view_path Rails.root.join('app', 'views', 'mailers')
layout 'mailer'
end
def registrant_confirm_url(domain:, method:)
token = domain.registrant_verification_token
base_url = ENV['registrant_portal_verifications_base_url']
url = registrant_domain_delete_confirm_url(domain, token: token) if method == 'delete'
url ||= registrant_domain_update_confirm_url(domain, token: token)
return url if base_url.blank?
"#{base_url}/confirmation/#{domain.name_puny}/#{method}/#{token}"
end
end

View file

@ -2,7 +2,7 @@ class DomainDeleteMailer < ApplicationMailer
def confirmation_request(domain:, registrar:, registrant:)
@domain = DomainPresenter.new(domain: domain, view: view_context)
@registrar = RegistrarPresenter.new(registrar: registrar, view: view_context)
@confirmation_url = confirmation_url(domain)
@confirmation_url = registrant_confirm_url(domain: domain, method: 'delete')
subject = default_i18n_subject(domain_name: domain.name)
mail(to: registrant.email, subject: subject)
@ -48,10 +48,6 @@ class DomainDeleteMailer < ApplicationMailer
private
def confirmation_url(domain)
registrant_domain_delete_confirm_url(domain, token: domain.registrant_verification_token)
end
def forced_email_from
ENV['action_mailer_force_delete_from'] || self.class.default[:from]
end

View file

@ -5,7 +5,7 @@ class RegistrantChangeMailer < ApplicationMailer
@domain = DomainPresenter.new(domain: domain, view: view_context)
@registrar = RegistrarPresenter.new(registrar: registrar, view: view_context)
@new_registrant = RegistrantPresenter.new(registrant: new_registrant, view: view_context)
@confirmation_url = confirmation_url(domain)
@confirmation_url = registrant_confirm_url(domain: domain, method: 'change')
subject = default_i18n_subject(domain_name: domain.name)
mail(to: current_registrant.email, subject: subject)
@ -49,10 +49,6 @@ class RegistrantChangeMailer < ApplicationMailer
private
def confirmation_url(domain)
registrant_domain_update_confirm_url(domain, token: domain.registrant_verification_token)
end
def address_processing
Contact.address_processing?
end

View file

@ -0,0 +1,81 @@
module Actions
class ContactCreate
attr_reader :contact, :legal_document, :ident
def initialize(contact, legal_document, ident)
@contact = contact
@legal_document = legal_document
@ident = ident
end
def call
maybe_remove_address
maybe_attach_legal_doc
validate_ident
commit
end
def maybe_remove_address
return if Contact.address_processing?
contact.city = nil
contact.zip = nil
contact.street = nil
contact.state = nil
contact.country_code = nil
end
def validate_ident
validate_ident_integrity
validate_ident_birthday
identifier = ::Contact::Ident.new(code: ident[:ident], type: ident[:ident_type],
country_code: ident[:ident_country_code])
identifier.validate
contact.identifier = identifier
end
def validate_ident_integrity
return if ident.blank?
if ident[:ident_type].blank?
contact.add_epp_error('2003', nil, 'ident_type',
I18n.t('errors.messages.required_ident_attribute_missing'))
@error = true
elsif !%w[priv org birthday].include?(ident[:ident_type])
contact.add_epp_error('2003', nil, 'ident_type', 'Invalid ident type')
@error = true
end
end
def validate_ident_birthday
return if ident.blank?
return unless ident[:ident_type] != 'birthday' && ident[:ident_country_code].blank?
contact.add_epp_error('2003', nil, 'ident_country_code',
I18n.t('errors.messages.required_ident_attribute_missing'))
@error = true
end
def maybe_attach_legal_doc
return unless legal_document
doc = LegalDocument.create(
documentable_type: Contact,
document_type: legal_document[:type], body: legal_document[:body]
)
contact.legal_documents = [doc]
contact.legal_document_id = doc.id
end
def commit
contact.id = nil # new record
return false if @error
contact.generate_code
contact.save
end
end
end

View file

@ -0,0 +1,41 @@
module Actions
class ContactDelete
attr_reader :contact
attr_reader :new_attributes
attr_reader :legal_document
attr_reader :ident
attr_reader :user
def initialize(contact, legal_document = nil)
@legal_document = legal_document
@contact = contact
end
def call
maybe_attach_legal_doc
if contact.linked?
contact.errors.add(:domains, :exist)
return
end
commit
end
def maybe_attach_legal_doc
return unless legal_document
document = contact.legal_documents.create(
document_type: legal_document[:type],
body: legal_document[:body]
)
contact.legal_document_id = document.id
contact.save
end
def commit
contact.destroy
end
end
end

View file

@ -17,7 +17,7 @@ module Actions
def call
maybe_remove_address
maybe_update_statuses
maybe_update_ident
maybe_update_ident if ident.present?
maybe_attach_legal_doc
commit
end
@ -53,7 +53,11 @@ module Actions
end
def maybe_update_ident
return unless ident[:ident]
unless ident.is_a?(Hash)
contact.add_epp_error('2308', nil, nil, I18n.t('epp.contacts.errors.valid_ident'))
@error = true
return
end
if contact.identifier.valid?
submitted_ident = ::Contact::Ident.new(code: ident[:ident],

View file

@ -0,0 +1,74 @@
module Actions
class DomainTransfer
attr_reader :domain
attr_reader :transfer_code
attr_reader :legal_document
attr_reader :ident
attr_reader :user
def initialize(domain, transfer_code, user)
@domain = domain
@transfer_code = transfer_code
@user = user
end
def call
return unless domain_exists?
return unless valid_transfer_code?
run_validations
# return domain.pending_transfer if domain.pending_transfer
# attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call)
return if domain.errors[:epp_errors].any?
commit
end
def domain_exists?
return true if domain.persisted?
domain.add_epp_error('2303', nil, nil, 'Object does not exist')
false
end
def run_validations
validate_registrar
validate_eligilibty
validate_not_discarded
end
def valid_transfer_code?
return true if transfer_code == domain.transfer_code
domain.add_epp_error('2202', nil, nil, 'Invalid authorization information')
false
end
def validate_registrar
return unless user == domain.registrar
domain.add_epp_error('2002', nil, nil,
I18n.t(:domain_already_belongs_to_the_querying_registrar))
end
def validate_eligilibty
return unless domain.non_transferable?
domain.add_epp_error('2304', nil, nil, 'Object status prohibits operation')
end
def validate_not_discarded
return unless domain.discarded?
domain.add_epp_error('2106', nil, nil, 'Object is not eligible for transfer')
end
def commit
bare_domain = Domain.find(domain.id)
::DomainTransfer.request(bare_domain, user)
end
end
end

View file

@ -52,51 +52,14 @@ module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength
force_delete_start + Setting.expire_warning_period.days <= valid_to
end
def schedule_force_delete(type: :fast_track)
if discarded?
raise StandardError, 'Force delete procedure cannot be scheduled while a domain is discarded'
end
type == :fast_track ? force_delete_fast_track : force_delete_soft
end
def add_force_delete_type(force_delete_type)
self.force_delete_type = force_delete_type
end
def force_delete_fast_track
preserve_current_statuses_for_force_delete
add_force_delete_statuses
add_force_delete_type(:fast)
self.force_delete_date = force_delete_fast_track_start_date + 1.day
self.force_delete_start = Time.zone.today + 1.day
stop_all_pending_actions
allow_deletion
save(validate: false)
end
def force_delete_soft
preserve_current_statuses_for_force_delete
add_force_delete_statuses
add_force_delete_type(:soft)
calculate_soft_delete_date
stop_all_pending_actions
allow_deletion
save(validate: false)
end
def clear_force_delete_data
self.force_delete_data = nil
def schedule_force_delete(type: :fast_track, notify_by_email: false)
ForceDeleteInteraction::SetForceDelete.run(domain: self,
type: type,
notify_by_email: notify_by_email)
end
def cancel_force_delete
remove_force_delete_statuses
restore_statuses_before_force_delete
clear_force_delete_data
self.force_delete_date = nil
self.force_delete_start = nil
save(validate: false)
registrar.notifications.create!(text: I18n.t('force_delete_cancelled', domain_name: name))
CancelForceDeleteInteraction::CancelForceDelete.run(domain: self)
end
def outzone_date
@ -107,55 +70,4 @@ module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength
(force_delete_date&.beginning_of_day || valid_to + Setting.expire_warning_period.days +
Setting.redemption_grace_period.days)
end
private
def calculate_soft_delete_date
years = (valid_to.to_date - Time.zone.today).to_i / 365
soft_delete_dates(years) if years.positive?
end
def soft_delete_dates(years)
self.force_delete_start = valid_to - years.years
self.force_delete_date = force_delete_start + Setting.expire_warning_period.days +
Setting.redemption_grace_period.days
end
def stop_all_pending_actions
statuses.delete(DomainStatus::PENDING_UPDATE)
statuses.delete(DomainStatus::PENDING_TRANSFER)
statuses.delete(DomainStatus::PENDING_RENEW)
statuses.delete(DomainStatus::PENDING_CREATE)
end
def preserve_current_statuses_for_force_delete
update(statuses_before_force_delete: statuses)
end
def restore_statuses_before_force_delete
self.statuses = statuses_before_force_delete
self.statuses_before_force_delete = nil
end
def add_force_delete_statuses
self.statuses |= [DomainStatus::FORCE_DELETE,
DomainStatus::SERVER_RENEW_PROHIBITED,
DomainStatus::SERVER_TRANSFER_PROHIBITED]
end
def remove_force_delete_statuses
statuses.delete(DomainStatus::FORCE_DELETE)
statuses.delete(DomainStatus::SERVER_RENEW_PROHIBITED)
statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED)
statuses.delete(DomainStatus::CLIENT_HOLD)
end
def allow_deletion
statuses.delete(DomainStatus::CLIENT_DELETE_PROHIBITED)
statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED)
end
def force_delete_fast_track_start_date
Time.zone.today + Setting.expire_warning_period.days + Setting.redemption_grace_period.days
end
end

View file

@ -333,31 +333,6 @@ class Contact < ApplicationRecord
Country.new(country_code)
end
# TODO: refactor, it should not allow to destroy with normal destroy,
# no need separate method
# should use only in transaction
def destroy_and_clean frame
if linked?
errors.add(:domains, :exist)
return false
end
legal_document_data = ::Deserializers::Xml::LegalDocument.new(frame).call
if legal_document_data
doc = LegalDocument.create(
documentable_type: Contact,
document_type: legal_document_data[:type],
body: legal_document_data[:body]
)
self.legal_documents = [doc]
self.legal_document_id = doc.id
self.save
end
destroy
end
def to_upcase_country_code
self.ident_country_code = ident_country_code.upcase if ident_country_code
self.country_code = country_code.upcase if country_code

View file

@ -418,7 +418,7 @@ class Domain < ApplicationRecord
pending_delete_confirmation!
save(validate: false) # should check if this did succeed
DomainDeleteConfirmEmailJob.enqueue(id)
DomainDeleteConfirmInteraction::SendRequest.run(domain: self)
end
def cancel_pending_delete

View file

@ -30,12 +30,13 @@ class Epp::Contact < Contact
at
end
def new(frame, registrar)
def new(frame, registrar, epp: true)
return super if frame.blank?
attrs = epp ? attrs_from(frame, new_record: true) : frame
super(
attrs_from(frame, new_record: true).merge(
code: frame.css('id').text,
attrs.merge(
code: epp ? frame.css('id').text : frame[:id],
registrar: registrar
)
)

View file

@ -137,7 +137,8 @@ class Registrar < ApplicationRecord
def api_ip_white?(ip)
return true unless Setting.api_ip_whitelist_enabled
white_ips.api.pluck(:ipv4, :ipv6).flatten.include?(ip)
white_ips.api.include_ip?(ip)
end
# Audit log is needed, therefore no raw SQL

View file

@ -2,8 +2,8 @@ class WhiteIp < ApplicationRecord
include Versions
belongs_to :registrar
validates :ipv4, format: { with: /\A(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\z/, allow_blank: true }
validates :ipv6, format: { with: /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/, allow_blank: true }
validate :valid_ipv4?
validate :valid_ipv6?
validate :validate_ipv4_and_ipv6
def validate_ipv4_and_ipv6
@ -11,6 +11,22 @@ class WhiteIp < ApplicationRecord
errors.add(:base, I18n.t(:ipv4_or_ipv6_must_be_present))
end
def valid_ipv4?
return if ipv4.blank?
IPAddr.new(ipv4, Socket::AF_INET)
rescue StandardError => _e
errors.add(:ipv4, :invalid)
end
def valid_ipv6?
return if ipv6.blank?
IPAddr.new(ipv6, Socket::AF_INET6)
rescue StandardError => _e
errors.add(:ipv6, :invalid)
end
API = 'api'
REGISTRAR = 'registrar'
INTERFACES = [API, REGISTRAR]
@ -23,8 +39,37 @@ class WhiteIp < ApplicationRecord
end
class << self
# rubocop:disable Style/CaseEquality
# rubocop:disable Metrics/AbcSize
def include_ip?(ip)
where('ipv4 = :ip OR ipv6 = :ip', ip: ip).any?
return false if ip.blank?
where(id: ids_including(ip)).any?
end
def ids_including(ip)
ipv4 = ipv6 = []
if check_ip4(ip).present?
ipv4 = select { |white_ip| IPAddr.new(white_ip.ipv4, Socket::AF_INET) === check_ip4(ip) }
end
if check_ip6(ip).present?
ipv6 = select { |white_ip| IPAddr.new(white_ip.ipv6, Socket::AF_INET6) === check_ip6(ip) }
end
(ipv4 + ipv6).pluck(:id).flatten.uniq
end
# rubocop:enable Style/CaseEquality
# rubocop:enable Metrics/AbcSize
def check_ip4(ip)
IPAddr.new(ip, Socket::AF_INET)
rescue StandardError => _e
nil
end
def check_ip6(ip)
IPAddr.new(ip, Socket::AF_INET6)
rescue StandardError => _e
nil
end
end
end

View file

@ -5,6 +5,7 @@ class RegistrantChange
end
def confirm
Dispute.close_by_domain(@domain.name) if @domain.disputed?
notify_registrant
end

View file

@ -14,11 +14,15 @@ xml.epp_head do
end
xml.tag!('contact:postalInfo', type: 'int') do
xml.tag!('contact:name', @contact.name)
if can? :view_full_info, @contact, @password
xml.tag!('contact:name', @contact.name)
else
xml.tag!('contact:name', 'No access')
end
if can? :view_full_info, @contact, @password
xml.tag!('contact:org', @contact.org_name) if @contact.org_name.present?
if address_processing?
if Contact.address_processing?
xml.tag!('contact:addr') do
xml.tag!('contact:street', @contact.street)
xml.tag!('contact:city', @contact.city)
@ -31,7 +35,7 @@ xml.epp_head do
else
xml.tag!('contact:org', 'No access')
if address_processing?
if Contact.address_processing?
xml.tag!('contact:addr') do
xml.tag!('contact:street', 'No access')
xml.tag!('contact:city', 'No access')

View file

@ -2,7 +2,7 @@
<p>Lugupeetud .ee domeeni registreerija/halduskontakt</p>
<p>Domeeninimi <%= @domain.name %> on aegunud ja ei ole alates <%= @domain.on_hold_date %> internetis kättesaadav. Domeeniga on seotud puudulike kontakti objekte, milles tulenevalt on Eesti Interneti SA blokeerinud domeeni pikendamise ja registripidaja vahetuse, kuniks kontaktandmed korrastatakse. Andmete korrastamiseks ja registreeringu pikendamiseks pöörduge palun oma registripidaja poole.</p>
<p>Domeeninimi <%= @domain.name %> on aegunud ja ei ole alates <%= @domain.on_hold_date %> internetis kättesaadav. Domeeniga on seotud puudulikke kontakti objekte, millest tulenevalt on Eesti Interneti SA blokeerinud domeeni pikendamise ja registripidaja vahetuse, kuniks kontaktandmed korrastatakse. Andmete korrastamiseks ja registreeringu pikendamiseks pöörduge palun oma registripidaja poole.</p>
<p><%= @domain.name %> pikendamata jätmisel domeen kustub ja läheb <%= @domain.delete_date %> oksjonile .ee oksjonikeskkonda. Domeenioksjonite kohta loe lähemalt <a href="https://www.internet.ee/domeenioksjonid">siit</a>.</p>

View file

@ -2,7 +2,7 @@ Domeen <%= @domain.name %> on aegunud ning suunatud kustutusmenetlusse kuna olem
Lugupeetud .ee domeeni registreerija/halduskontakt
Domeeninimi <%= @domain.name %> on aegunud ja ei ole alates <%= @domain.on_hold_date %> internetis kättesaadav. Domeeniga on seotud puudulike kontakti objekte, milles tulenevalt on Eesti Interneti SA blokeerinud domeeni pikendamise ja registripidaja vahetuse, kuniks kontaktandmed korrastatakse. Andmete korrastamiseks ja registreeringu pikendamiseks pöörduge palun oma registripidaja poole.
Domeeninimi <%= @domain.name %> on aegunud ja ei ole alates <%= @domain.on_hold_date %> internetis kättesaadav. Domeeniga on seotud puudulikke kontakti objekte, millest tulenevalt on Eesti Interneti SA blokeerinud domeeni pikendamise ja registripidaja vahetuse, kuniks kontaktandmed korrastatakse. Andmete korrastamiseks ja registreeringu pikendamiseks pöörduge palun oma registripidaja poole.
<%= @domain.name %> pikendamata jätmisel domeen kustub ja läheb <%= @domain.delete_date %> oksjonile .ee oksjonikeskkonda. Domeenioksjonite kohta loe lähemalt siit https://www.internet.ee/domeenioksjonid.

View file

@ -5,7 +5,7 @@
.col-md-8
= render 'registrar/contacts/form/general', f: f
- if address_processing?
- if Contact.address_processing?
.row
.col-md-8
= render 'registrar/contacts/form/address', f: f

View file

@ -13,5 +13,5 @@
- registrant = Contact.find_by_code(x.text)
%tr
%td= x['type']
%td= registrant.name
%td= registrant.registrar == current_registrar_user.registrar ? registrant.name : 'N/A'
%td= x.text

View file

@ -23,7 +23,7 @@
<% registrant = Contact.find_by_code(@data.css('registrant').text) %>
<dt><%= t('.registrant') %></dt>
<dd><%= "#{registrant.name} (#{@data.css('registrant').text})" %></dd>
<dd><%= registrant.registrar == current_registrar_user.registrar ? "#{registrant.name} (#{@data.css('registrant').text})" : @data.css('registrant').text %></dd>
<dt><%= t('.registered') %></dt>
<dd><%= @data.css('crDate').text %></dd>