mirror of
https://github.com/internetee/registry.git
synced 2025-06-04 11:47:30 +02:00
Add disputing logic for EPP
This commit is contained in:
parent
7a7b2f9881
commit
0f2a290d64
17 changed files with 626 additions and 325 deletions
|
@ -28,9 +28,8 @@ module Admin
|
|||
# POST /admin/disputes
|
||||
def create
|
||||
@dispute = Dispute.new(dispute_params)
|
||||
|
||||
if @dispute.save
|
||||
redirect_to @dispute, notice: 'Dispute was successfully created.'
|
||||
redirect_to admin_disputes_url, notice: 'Dispute was successfully created.'
|
||||
else
|
||||
render :new
|
||||
end
|
||||
|
@ -39,16 +38,16 @@ module Admin
|
|||
# PATCH/PUT /admin/disputes/1
|
||||
def update
|
||||
if @dispute.update(dispute_params)
|
||||
redirect_to @dispute, notice: 'Dispute was successfully updated.'
|
||||
redirect_to admin_disputes_url, notice: 'Dispute was successfully updated.'
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /admin/disputes/1
|
||||
def destroy
|
||||
def delete
|
||||
@dispute.destroy
|
||||
redirect_to disputes_url, notice: 'Dispute was successfully destroyed.'
|
||||
redirect_to admin_disputes_url, notice: 'Dispute was successfully destroyed.'
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -60,7 +59,7 @@ module Admin
|
|||
|
||||
# Only allow a trusted parameter "white list" through.
|
||||
def dispute_params
|
||||
params.require(:dispute).permit(:domain_name, :password, :expires_at, :comment, :created_at)
|
||||
params.require(:dispute).permit(:domain_name, :password, :starts_at, :comment)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -104,6 +104,10 @@ module Epp
|
|||
authorize! :update, @domain, @password
|
||||
|
||||
if @domain.update(params[:parsed_frame], current_user)
|
||||
if @domain.disputed?
|
||||
dispute = Dispute.active.find_by(domain_name: @domain.name)
|
||||
dispute.close
|
||||
end
|
||||
if @domain.epp_pending_update.present?
|
||||
render_epp_response '/epp/domains/success_pending'
|
||||
else
|
||||
|
|
|
@ -31,6 +31,12 @@ class Registrant::DomainUpdateConfirmsController < RegistrantController
|
|||
end
|
||||
elsif params[:confirmed]
|
||||
if @registrant_verification.domain_registrant_change_confirm!("email link, #{initiator}")
|
||||
if @domain.disputed?
|
||||
Rails.logger.info 'Closing domain dispute via RegistrantConfirmation'
|
||||
dispute = Dispute.active.find_by(domain_name: @domain.name)
|
||||
dispute.close
|
||||
end
|
||||
|
||||
flash[:notice] = t(:registrant_domain_verification_confirmed)
|
||||
redirect_to registrant_domain_update_confirm_path(@domain.id, confirmed: true)
|
||||
else
|
||||
|
|
|
@ -4,10 +4,11 @@ class UpdateWhoisRecordJob < Que::Job
|
|||
::PaperTrail.whodunnit = "job - #{self.class.name} - #{type}"
|
||||
|
||||
klass = case type
|
||||
when 'reserved'then ReservedDomain
|
||||
when 'blocked' then BlockedDomain
|
||||
when 'domain' then Domain
|
||||
end
|
||||
when 'reserved' then ReservedDomain
|
||||
when 'blocked' then BlockedDomain
|
||||
when 'domain' then Domain
|
||||
when 'disputed' then Dispute
|
||||
end
|
||||
|
||||
Array(names).each do |name|
|
||||
record = klass.find_by(name: name)
|
||||
|
@ -19,8 +20,6 @@ class UpdateWhoisRecordJob < Que::Job
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def update_domain(domain)
|
||||
domain.whois_record ? domain.whois_record.save : domain.create_whois_record
|
||||
end
|
||||
|
@ -33,6 +32,9 @@ class UpdateWhoisRecordJob < Que::Job
|
|||
update_reserved(record)
|
||||
end
|
||||
|
||||
def update_disputed(record)
|
||||
update_reserved(record)
|
||||
end
|
||||
|
||||
# 1. deleting own
|
||||
# 2. trying to regenerate reserved in order domain is still in the list
|
||||
|
@ -41,6 +43,7 @@ class UpdateWhoisRecordJob < Que::Job
|
|||
|
||||
BlockedDomain.find_by(name: name).try(:generate_data)
|
||||
ReservedDomain.find_by(name: name).try(:generate_data)
|
||||
Dispute.active.find_by(domain_name: name).try(:generate_data)
|
||||
end
|
||||
|
||||
def delete_reserved(name)
|
||||
|
@ -51,4 +54,8 @@ class UpdateWhoisRecordJob < Que::Job
|
|||
def delete_blocked(name)
|
||||
delete_reserved(name)
|
||||
end
|
||||
|
||||
def delete_disputed(name)
|
||||
delete_reserved(name)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,89 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Dispute < ApplicationRecord
|
||||
validates :domain_name, :password, :starts_at, :expires_at, :comment,
|
||||
presence: true
|
||||
validates :domain_name, :password, :starts_at, :expires_at, presence: true
|
||||
validates_uniqueness_of :domain_name, case_sensitive: true
|
||||
before_validation :fill_empty_passwords
|
||||
before_validation :set_expiry_date
|
||||
validate :validate_domain_name
|
||||
|
||||
with_options on: :admin do
|
||||
validate :validate_start_date
|
||||
end
|
||||
before_save :set_expiry_date
|
||||
before_save :sync_reserved_password
|
||||
after_destroy :remove_data
|
||||
|
||||
scope :expired, -> { where('expires_at < ?', Time.zone.today) }
|
||||
scope :active, -> { where('expires_at > ? AND closed = 0', Time.zone.today) }
|
||||
scope :closed, -> { where(closed: true) }
|
||||
|
||||
alias_attribute :name, :domain_name
|
||||
|
||||
def set_expiry_date
|
||||
return if starts_at.blank?
|
||||
|
||||
self.expires_at = starts_at + Setting.dispute_period_in_months.months
|
||||
end
|
||||
|
||||
def generate_password
|
||||
self.password = SecureRandom.hex
|
||||
end
|
||||
|
||||
def generate_data
|
||||
return if Domain.where(name: domain_name).any?
|
||||
|
||||
wr = Whois::Record.find_or_initialize_by(name: domain_name)
|
||||
wr.json = @json = generate_json # we need @json to bind to class
|
||||
wr.save
|
||||
end
|
||||
|
||||
def close
|
||||
self.closed = true
|
||||
save!
|
||||
end
|
||||
|
||||
def generate_json
|
||||
h = HashWithIndifferentAccess.new
|
||||
h[:name] = domain_name
|
||||
h[:status] = ['Disputed']
|
||||
h
|
||||
end
|
||||
|
||||
def remove_data
|
||||
UpdateWhoisRecordJob.enqueue domain_name, 'disputed'
|
||||
end
|
||||
|
||||
def fill_empty_passwords
|
||||
generate_password if password.blank?
|
||||
end
|
||||
|
||||
def sync_reserved_password
|
||||
reserved_domain = ReservedDomain.find_by(name: domain_name)
|
||||
generate_password if password.blank?
|
||||
|
||||
unless reserved_domain.nil?
|
||||
reserved_domain.password = password
|
||||
reserved_domain.save!
|
||||
end
|
||||
|
||||
generate_data
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_start_date
|
||||
return if starts_at.nil?
|
||||
|
||||
errors.add(:starts_at, :past) if starts_at.past?
|
||||
end
|
||||
|
||||
def validate_domain_name
|
||||
return unless domain_name
|
||||
|
||||
zone = domain_name.split('.').last
|
||||
supported_zone = DNS::Zone.origins.include?(zone)
|
||||
|
||||
errors.add(:domain_name, :unsupported_zone) unless supported_zone
|
||||
end
|
||||
end
|
||||
|
|
|
@ -68,6 +68,10 @@ module DNS
|
|||
ReservedDomain.where(name: name).any?
|
||||
end
|
||||
|
||||
def disputed?
|
||||
Dispute.active.where(domain_name: name).any?
|
||||
end
|
||||
|
||||
def auctionable?
|
||||
!not_auctionable?
|
||||
end
|
||||
|
@ -81,7 +85,7 @@ module DNS
|
|||
attr_reader :name
|
||||
|
||||
def not_auctionable?
|
||||
blocked? || reserved?
|
||||
blocked? || reserved? || disputed?
|
||||
end
|
||||
|
||||
def zone_with_same_origin?
|
||||
|
|
|
@ -90,6 +90,7 @@ class Domain < ApplicationRecord
|
|||
validates :transfer_code, presence: true
|
||||
|
||||
validate :validate_reservation
|
||||
|
||||
def validate_reservation
|
||||
return if persisted? || !in_reserved_list?
|
||||
|
||||
|
@ -99,6 +100,7 @@ class Domain < ApplicationRecord
|
|||
end
|
||||
|
||||
return if ReservedDomain.pw_for(name) == reserved_pw
|
||||
|
||||
errors.add(:base, :invalid_auth_information_reserved)
|
||||
end
|
||||
|
||||
|
@ -170,7 +172,7 @@ class Domain < ApplicationRecord
|
|||
end
|
||||
|
||||
attr_accessor :registrant_typeahead, :update_me,
|
||||
:epp_pending_update, :epp_pending_delete, :reserved_pw
|
||||
:epp_pending_update, :epp_pending_delete, :reserved_pw, :disputed_pw
|
||||
|
||||
self.ignored_columns = %w[legacy_id legacy_registrar_id legacy_registrant_id]
|
||||
|
||||
|
@ -275,6 +277,10 @@ class Domain < ApplicationRecord
|
|||
@in_reserved_list ||= ReservedDomain.by_domain(name).any?
|
||||
end
|
||||
|
||||
def disputed?
|
||||
Dispute.active.where(domain_name: name).any?
|
||||
end
|
||||
|
||||
def pending_transfer
|
||||
transfers.find_by(status: DomainTransfer::PENDING)
|
||||
end
|
||||
|
|
|
@ -58,7 +58,8 @@ class Epp::Domain < Domain
|
|||
'2003' => [ # Required parameter missing
|
||||
[:registrant, :blank],
|
||||
[:registrar, :blank],
|
||||
[:base, :required_parameter_missing_reserved]
|
||||
[:base, :required_parameter_missing_reserved],
|
||||
[:base, :required_parameter_missing_disputed]
|
||||
],
|
||||
'2004' => [ # Parameter value range error
|
||||
[:dnskeys, :out_of_range,
|
||||
|
@ -88,7 +89,8 @@ class Epp::Domain < Domain
|
|||
[:transfer_code, :wrong_pw]
|
||||
],
|
||||
'2202' => [
|
||||
[:base, :invalid_auth_information_reserved]
|
||||
[:base, :invalid_auth_information_reserved],
|
||||
[:base, :invalid_auth_information_disputed]
|
||||
],
|
||||
'2302' => [ # Object exists
|
||||
[:name_dirty, :taken, { value: { obj: 'name', val: name_dirty } }],
|
||||
|
@ -154,6 +156,7 @@ class Epp::Domain < Domain
|
|||
at[:period_unit] = Epp::Domain.parse_period_unit_from_frame(frame) || 'y'
|
||||
|
||||
at[:reserved_pw] = frame.css('reserved > pw').text
|
||||
at[:disputed_pw] = frame.css('disputed > pw').text
|
||||
|
||||
# at[:statuses] = domain_statuses_attrs(frame, action)
|
||||
at[:nameservers_attributes] = nameservers_attrs(frame, action)
|
||||
|
@ -475,6 +478,16 @@ class Epp::Domain < Domain
|
|||
|
||||
same_registrant_as_current = (registrant.code == frame.css('registrant').text)
|
||||
|
||||
if !same_registrant_as_current && disputed?
|
||||
disputed_pw = frame.css('disputed > pw').text
|
||||
if disputed_pw.blank?
|
||||
add_epp_error('2304', nil, nil, 'Required parameter missing; disputed pw element required for dispute domains')
|
||||
else
|
||||
dispute = Dispute.active.find_by(domain_name: name, password: disputed_pw)
|
||||
add_epp_error('2202', nil, nil, 'Invalid authorization information; invalid disputed>pw value') if dispute.nil?
|
||||
end
|
||||
end
|
||||
|
||||
if !same_registrant_as_current && errors.empty? && verify &&
|
||||
Setting.request_confrimation_on_registrant_change_enabled &&
|
||||
frame.css('registrant').present? &&
|
||||
|
@ -706,6 +719,11 @@ class Epp::Domain < Domain
|
|||
|
||||
|
||||
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
|
||||
|
|
|
@ -46,6 +46,7 @@ class Setting < RailsSettings::Base
|
|||
expire_warning_period
|
||||
redemption_grace_period
|
||||
expire_pending_confirmation
|
||||
dispute_period_in_months
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -44,6 +44,8 @@ defaults: &defaults
|
|||
registrar_ip_whitelist_enabled: false
|
||||
api_ip_whitelist_enabled: false
|
||||
|
||||
dispute_period_in_months: 36
|
||||
|
||||
registry_juridical_name: "Eesti Interneti SA"
|
||||
registry_reg_no: "90010019"
|
||||
registry_email: "info@internet.ee"
|
||||
|
|
|
@ -8,3 +8,5 @@ en:
|
|||
|
||||
form:
|
||||
password_hint: Generated automatically if left blank
|
||||
optional: Not required by default
|
||||
in_future: Must be at least today / in future
|
||||
|
|
|
@ -24,6 +24,8 @@ en:
|
|||
key_data_not_allowed: 'keyData object is not allowed'
|
||||
required_parameter_missing_reserved: 'Required parameter missing; reserved>pw element required for reserved domains'
|
||||
invalid_auth_information_reserved: 'Invalid authorization information; invalid reserved>pw value'
|
||||
required_parameter_missing_disputed: 'Required parameter missing; disputed pw element required for dispute domains'
|
||||
invalid_auth_information_disputed: 'Invalid authorization information; invalid disputed>pw value'
|
||||
domain_name_blocked: 'Data management policy violation: Domain name is blocked [name]'
|
||||
name_dirty:
|
||||
invalid: 'Domain name is invalid'
|
||||
|
@ -631,6 +633,7 @@ en:
|
|||
add_blocked_domain: 'Add domain to blocked list'
|
||||
add_disputed_domain: 'Add domain to disputed list'
|
||||
edit_pw: 'Edit Pw'
|
||||
edit_dispute: 'Edit dispute'
|
||||
optional: 'Optional'
|
||||
test_registrar: "Test registrar"
|
||||
verified_confirm: 'Verified status is for cases when current registrant is the one applying for the update. Legal document signed by the registrant is required. Are you sure this update is properly verified with the registrant?'
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
require_dependency 'epp_constraint'
|
||||
|
||||
Rails.application.routes.draw do
|
||||
resources :disputes
|
||||
# https://github.com/internetee/epp_proxy#translation-of-epp-calls
|
||||
namespace :epp do
|
||||
constraints(EppConstraint.new(:session)) do
|
||||
|
@ -259,7 +258,11 @@ Rails.application.routes.draw do
|
|||
get 'delete'
|
||||
end
|
||||
end
|
||||
resources :disputes
|
||||
resources :disputes do
|
||||
member do
|
||||
get 'delete'
|
||||
end
|
||||
end
|
||||
|
||||
resources :registrars do
|
||||
resources :api_users, except: %i[index]
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
class CreateDisputes < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :disputes do |t|
|
||||
t.string :domain_name
|
||||
t.string :password
|
||||
t.date :expires_at
|
||||
t.date :starts_at
|
||||
t.string :domain_name, null: false
|
||||
t.string :password, null: false
|
||||
t.date :expires_at, null: false
|
||||
t.date :starts_at, null: false
|
||||
t.text :comment
|
||||
t.datetime :created_at
|
||||
t.boolean :closed, null: false, default: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
|
746
db/structure.sql
746
db/structure.sql
File diff suppressed because it is too large
Load diff
|
@ -25,6 +25,7 @@
|
|||
<element name="ident" type="eis:identType" minOccurs="0" maxOccurs="1"/>
|
||||
<element name="legalDocument" type="eis:legalDocType" minOccurs="0" maxOccurs="1"/>
|
||||
<element name="reserved" type="eis:reservedType" minOccurs="0" maxOccurs="1"/>
|
||||
<element name="disputed" type="eis:disputedType" minOccurs="0" maxOccurs="1"/>
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
|
@ -49,6 +50,16 @@
|
|||
</restriction>
|
||||
</simpleType>
|
||||
|
||||
<!--
|
||||
Disputed for providing passwords for disputed domains
|
||||
-->
|
||||
|
||||
<complexType name="disputedType">
|
||||
<sequence>
|
||||
<element name="pw" type="eis:pwType" minOccurs="0" maxOccurs="1"/>
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
<!--
|
||||
Legal document, encoded in base64
|
||||
-->
|
||||
|
|
|
@ -35,6 +35,11 @@ namespace :whois do
|
|||
ReservedDomain.find_in_batches.each do |group|
|
||||
UpdateWhoisRecordJob.enqueue group.map(&:name), 'reserved'
|
||||
end
|
||||
|
||||
print "\n-----> Update disputed domains whois_records"
|
||||
Dispute.active.find_in_batches.each do |group|
|
||||
UpdateWhoisRecordJob.enqueue group.map(&:domain_name), 'disputed'
|
||||
end
|
||||
end
|
||||
puts "\n-----> all done in #{(Time.zone.now.to_f - start).round(2)} seconds"
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue