Merge branch 'master' of https://github.com/internetee/registry into 39-registrant-confirmation-should-not-be-asked

This commit is contained in:
Oleg Hasjanov 2021-03-12 10:40:16 +02:00
commit 169318cd13
249 changed files with 3620 additions and 2725 deletions

View file

@ -7,14 +7,19 @@ prepare:
plugins:
brakeman:
enabled: true
checks:
mass_assign_permit!:
enabled: false
bundler-audit:
enabled: true
duplication:
enabled: true
config:
languages:
- ruby
- javascript
ruby:
mass_threshold: 100
javascript:
mass_threshold: 100
eslint:
enabled: true
channel: eslint-5
@ -26,6 +31,9 @@ plugins:
rubocop:
enabled: true
channel: rubocop-0-74
checks:
Rubocop/Style/ClassAndModuleChildren:
enabled: false
checks:
method-lines:
config:

View file

@ -17,7 +17,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-18.04]
ruby: [2.6, 2.7 ]
ruby: [ 2.7 ]
runs-on: ${{ matrix.os }}
continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }}
steps:
@ -100,11 +100,6 @@ jobs:
- name: Give test coverage reporter executable permissions
run: chmod +x cc-test-reporter
- uses: actions/download-artifact@v1
with:
name: coverage-2.6
path: coverage
- uses: actions/download-artifact@v1
with:
name: coverage-2.7

View file

@ -1 +1 @@
2.6.5
2.7.2

View file

@ -1,3 +1,81 @@
12.03.2021
* Removed old classnames from notifications [#1878](https://github.com/internetee/registry/pull/1878)
11.03.2021
* Account activity in registrar and REPP now return balance with each record [#1819](https://github.com/internetee/registry/issues/1819)
* Fixed CookieOverflow error with large authentication service keys [#1879](https://github.com/internetee/registry/pull/1879)
10.03.2021
* Registrant API returns full contact details for admin contacts [#1876](https://github.com/internetee/registry/pull/1876)
09.03.2021
* AWS message id saving over API [#1877](https://github.com/internetee/registry/pull/1877)
* Enabled Zeitwerk autoloader [#1872](https://github.com/internetee/registry/issues/1872)
04.03.2021
* Removed old registrant portal from the project [#1826](https://github.com/internetee/registry/issues/1826)
03.03.2021
* Email notification is sent in case of pendingupdate expiry [#897](https://github.com/internetee/registry/issues/897)
26.02.2021
* Domain delete is not affected by updateProhibited [#1844](https://github.com/internetee/registry/issues/1844)
* Registrant API fix for handling eidas personal identificators [#1864](https://github.com/internetee/registry/pull/1864)
23.02.2021
* UpdateProhibited status affects bulk actions in REPP [#1818](https://github.com/internetee/registry/issues/1818)
* Registrant api domain request now excludes tech only domains by default [#1836](https://github.com/internetee/registry/pull/1836)
22.02.2021
* serverDeleteProhibited prohibts delete action [#1849](https://github.com/internetee/registry/issues/1849)
19.02.2021
* Update prohibited staatus is kept after renew [#1843](https://github.com/internetee/registry/issues/1843)
* Fixed clientHold and serverManualInzone status conflict issue [#1845](https://github.com/internetee/registry/issues/1845)
* Replacing registrant object with another that has the same ident data set does not require registrant verification [#1852](https://github.com/internetee/registry/issues/1852)
11.02.2021
* Poll messages on locking and unlocking a domain [#1828](https://github.com/internetee/registry/issues/1828)
* Registrar's prefix is now checked and added to contact id for info and check requests [#1832](https://github.com/internetee/registry/issues/1832)
10.02.2021
* Admin contact bulk change option for registrars [#1764](https://github.com/internetee/registry/issues/1764)
* Option to remove email addresses from AWS SES Supression list [#1839](https://github.com/internetee/registry/issues/1839)
* Added separate key for bounce API [#1842](https://github.com/internetee/registry/pull/1842)
09.02.2021
* Added new endpoint for WHOIS contact requests [#1794](https://github.com/internetee/registry/pull/1794)
05.02.2021
* Fixed IPv4 empty string issue in case of IPv6 only entries for IP whitelist [#1833](https://github.com/internetee/registry/issues/1833)
02.02.2021
* Fixed updateProhibited status not affecting bulk tech contact change operation [#1820](https://github.com/internetee/registry/pull/1820)
01.02.2021
* Improved tests for admin interface [#1805](https://github.com/internetee/registry/pull/1805)
28.01.2021
* Fixed transfer with shared admin and tech contacts [#1808](https://github.com/internetee/registry/issues/1808)
* Improved error handling with double admin/tech contacts [#1758](https://github.com/internetee/registry/issues/1758)
* Added CSV export option to admin [#1775](https://github.com/internetee/registry/issues/1775)
* Improved DNSSEC key validation for illegal characters [#1790](https://github.com/internetee/registry/issues/1790)
* Fix for whois record creation issue on releasing domain to auction [#1139](https://github.com/internetee/registry/issues/1139)
* Fix for handling malformed request frames [#1825](https://github.com/internetee/registry/issues/1825)
* Improved registrar account activity tests [#1824](https://github.com/internetee/registry/pull/1824)
27.01.2021
* Figaro update to 1.2.0 [#1823](https://github.com/internetee/registry/pull/1823)
26.01.2021
* Ruby update to 2.7 [#1791](https://github.com/internetee/registry/issues/1791)
21.01.2021
* Registrant API: optimised contact linking [#1807](https://github.com/internetee/registry/pull/1807)
20.01.2021
* Fixed legaldoc assignment issue on registrant confirmation [#1806](https://github.com/internetee/registry/pull/1806)
14.01.2021
* Fixed IDN and punycode support for REPP domain transfer_info request [#1801](https://github.com/internetee/registry/issues/1801)

View file

@ -1,4 +1,4 @@
FROM internetee/ruby:2.6-buster
FROM internetee/ruby:2.7-buster
RUN mkdir -p /opt/webapps/app/tmp/pids
WORKDIR /opt/webapps/app

View file

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

View file

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

View file

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

View file

@ -2,12 +2,12 @@ module Admin
class ContactVersionsController < BaseController
include ObjectVersionsHelper
load_and_authorize_resource
load_and_authorize_resource class: Version::ContactVersion
def index
params[:q] ||= {}
@q = ContactVersion.search(params[:q])
@q = Version::ContactVersion.search(params[:q])
@versions = @q.result.page(params[:page])
search_params = params[:q].deep_dup
@ -23,7 +23,7 @@ module Admin
end
end
versions = ContactVersion.includes(:item).where(whereS).order(created_at: :desc, id: :desc)
versions = Version::ContactVersion.includes(:item).where(whereS).order(created_at: :desc, id: :desc)
@q = versions.search(params[:q])
@versions = @q.result.page(params[:page])
@versions = @versions.per(params[:results_per_page]) if params[:results_per_page].to_i.positive?
@ -32,8 +32,8 @@ module Admin
def show
per_page = 7
@version = ContactVersion.find(params[:id])
@versions = ContactVersion.where(item_id: @version.item_id).order(created_at: :desc, id: :desc)
@version = Version::ContactVersion.find(params[:id])
@versions = Version::ContactVersion.where(item_id: @version.item_id).order(created_at: :desc, id: :desc)
@versions_map = @versions.all.map(&:id)
# what we do is calc amount of results until needed version
@ -49,7 +49,7 @@ module Admin
end
def search
render json: ContactVersion.search_by_query(params[:q])
render json: Version::ContactVersion.search_by_query(params[:q])
end
def create_where_string(key, value)

View file

@ -2,12 +2,12 @@ module Admin
class DomainVersionsController < BaseController
include ObjectVersionsHelper
load_and_authorize_resource
load_and_authorize_resource class: Version::DomainVersion
def index
params[:q] ||= {}
@q = DomainVersion.includes(:item).search(params[:q])
@q = Version::DomainVersion.includes(:item).search(params[:q])
@versions = @q.result.page(params[:page])
search_params = params[:q].deep_dup
@ -40,7 +40,7 @@ module Admin
whereS += " AND object->>'registrar_id' IN (#{registrars.map { |r| "'#{r.id.to_s}'" }.join ','})" if registrars.present?
whereS += " AND 1=0" if registrars == []
versions = DomainVersion.includes(:item).where(whereS).order(created_at: :desc, id: :desc)
versions = Version::DomainVersion.includes(:item).where(whereS).order(created_at: :desc, id: :desc)
@q = versions.search(params[:q])
@versions = @q.result.page(params[:page])
@versions = @versions.per(params[:results_per_page]) if params[:results_per_page].to_i.positive?
@ -50,8 +50,8 @@ module Admin
def show
per_page = 7
@version = DomainVersion.find(params[:id])
@versions = DomainVersion.where(item_id: @version.item_id).order(created_at: :desc, id: :desc)
@version = Version::DomainVersion.find(params[:id])
@versions = Version::DomainVersion.where(item_id: @version.item_id).order(created_at: :desc, id: :desc)
@versions_map = @versions.all.map(&:id)
# what we do is calc amount of results until needed version
@ -67,7 +67,7 @@ module Admin
end
def search
render json: DomainVersion.search_by_query(params[:q])
render json: Version::DomainVersion.search_by_query(params[:q])
end
def create_where_string(key, value)

View file

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

View file

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

View file

@ -1,7 +1,7 @@
module Api
module V1
class BouncesController < BaseController
before_action :authenticate_shared_key
before_action :validate_shared_key_integrity
# POST api/v1/bounces/
def create
@ -20,6 +20,13 @@ module Api
params.require(:data)
end
private
def validate_shared_key_integrity
api_key = "Basic #{ENV['rwhois_bounces_api_shared_key']}"
head(:unauthorized) unless api_key == request.authorization
end
end
end
end

View file

@ -0,0 +1,38 @@
module Api
module V1
class ContactRequestsController < BaseController
before_action :authenticate_shared_key
# POST api/v1/contact_requests/
def create
return head(:bad_request) if contact_request_params[:email].blank?
contact_request = ContactRequest.save_record(contact_request_params)
render json: contact_request, status: :created
rescue StandardError
head(:bad_request)
end
def update
return head(:bad_request) if params[:id].blank?
process_id(params[:id])
end
def process_id(id)
record = ContactRequest.find_by(id: id)
return :not_found unless record
record.update_record(contact_request_params)
render json: record, status: :ok
rescue StandardError
head :bad_request
end
def contact_request_params
params.require(:contact_request).permit(:email, :whois_record_id, :name, :status, :ip,
:message_id)
end
end
end
end

View file

@ -19,6 +19,9 @@ module Api
token = create_token(user)
if token
msg = "Bearer for #{eid_params[:first_name]} #{eid_params[:last_name]} " \
"(#{eid_params[:ident]}) - '#{token[:access_token]}'"
ToStdout.msg(msg) unless Rails.env.production?
render json: token
else
render json: { errors: [{ base: ['Cannot create generate session token'] }] }
@ -37,7 +40,7 @@ module Api
obj.require(key)
end
params.permit(required_params)
params.permit(required_params + [:country_code])
end
def create_token(user)

View file

@ -24,7 +24,7 @@ module Api
end
def show
contact = current_user_contacts.find_by(uuid: params[:uuid])
contact = representable_contact(params[:uuid])
links = params[:links] == 'true'
if contact
@ -91,6 +91,22 @@ module Api
private
def representable_contact(uuid)
country = current_registrant_user.country.alpha2
contact = Contact.find_by(uuid: uuid, ident: current_registrant_user.ident,
ident_type: 'priv', ident_country_code: country)
return contact if contact
Contact.find_by(uuid: uuid, ident_type: 'org', ident: company_codes,
ident_country_code: country)
rescue CompanyRegister::NotAvailableError
nil
end
def company_codes
current_registrant_user.companies.collect(&:registration_number)
end
def current_user_contacts
current_registrant_user.contacts(representable: false)
rescue CompanyRegister::NotAvailableError

View file

@ -4,6 +4,8 @@ module Api
module V1
module Registrant
class DomainsController < ::Api::V1::Registrant::BaseController
before_action :set_tech_flag, only: [:show]
def index
limit = params[:limit] || 200
offset = params[:offset] || 0
@ -25,7 +27,8 @@ module Api
serializer.to_json
end
render json: { count: domains.count, domains: serialized_domains }
render json: { total: current_user_domains_total_count, count: domains.count,
domains: serialized_domains }
end
def show
@ -41,10 +44,22 @@ module Api
private
def current_user_domains
current_registrant_user.domains
def set_tech_flag
# current_user_domains scope depends on tech flag
# However, if it's not present, tech contact can not see specific domain entry at all.
params.merge!(tech: 'true')
end
def current_user_domains_total_count
current_registrant_user.domains.count
rescue CompanyRegister::NotAvailableError
current_registrant_user.direct_domains
current_registrant_user.direct_domains.count
end
def current_user_domains
current_registrant_user.domains(admin: params[:tech] != 'true')
rescue CompanyRegister::NotAvailableError
current_registrant_user.direct_domains(admin: params[:tech] != 'true')
end
end
end

View file

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

View file

@ -12,9 +12,11 @@ module Epp
@notification = current_user.unread_notifications.order('created_at DESC').take
render_epp_response 'epp/poll/poll_no_messages' and return unless @notification
if @notification.attached_obj_type && @notification.attached_obj_id
begin
@object = Object.const_get(@notification.attached_obj_type).find(@notification.attached_obj_id)
@object = object_by_type(@notification.attached_obj_type)
.find(@notification.attached_obj_id)
rescue => problem
# the data model might be inconsistent; or ...
# this could happen if the registrar does not dequeue messages, and then the domain was deleted
@ -31,6 +33,12 @@ module Epp
render_epp_response 'epp/poll/poll_req'
end
def object_by_type(object_type)
Object.const_get(object_type)
rescue NameError
Object.const_get("Version::#{object_type}")
end
def ack_poll
@notification = current_user.unread_notifications.find_by(id: params[:parsed_frame].css('poll').first['msgID'])

View file

@ -1,115 +0,0 @@
class Registrant::ContactsController < RegistrantController
helper_method :domain
helper_method :fax_enabled?
helper_method :domain_filter_params
skip_authorization_check only: %i[edit update]
before_action :set_contact, only: [:show]
def show
@requester_contact = Contact.find_by(ident: current_registrant_user.ident)
authorize! :read, @contact
end
def edit
@contact = current_user_contacts.find(params[:id])
end
def update
@contact = current_user_contacts.find(params[:id])
@contact.attributes = contact_params
response = update_contact_via_api(@contact.uuid)
updated = response.is_a?(Net::HTTPSuccess)
if updated
redirect_to registrant_domain_contact_url(domain, @contact), notice: t('.updated')
else
parsed_response = JSON.parse(response.body, symbolize_names: true)
@errors = parsed_response[:errors]
render :edit
end
end
private
def set_contact
id = params[:id]
contact = domain.contacts.find_by(id: id) || current_user_contacts.find_by(id: id)
contact ||= Contact.find_by(id: id, ident: domain.registrant.ident)
@contact = contact
end
def domain
current_user_domains.find(params[:domain_id])
end
def contact_params
permitted = %i[
name
email
phone
]
permitted << :fax if fax_enabled?
permitted += %i[street zip city state country_code] if Contact.address_processing?
params.require(:contact).permit(*permitted)
end
def access_token
uri = URI.parse("#{ENV['registrant_api_base_url']}/api/v1/registrant/auth/eid")
request = Net::HTTP::Post.new(uri)
request.form_data = access_token_request_params
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: (uri.scheme == 'https')) do |http|
http.request(request)
end
json_doc = JSON.parse(response.body, symbolize_names: true)
json_doc[:access_token]
end
def access_token_request_params
{ ident: current_registrant_user.ident,
first_name: current_registrant_user.first_name,
last_name: current_registrant_user.last_name }
end
def fax_enabled?
ENV['fax_enabled'] == 'true'
end
def contact_update_api_params
params = contact_params
params = normalize_address_attributes_for_api(params) if Contact.address_processing?
params
end
def normalize_address_attributes_for_api(params)
normalized = params
address_parts = {}
Contact.address_attribute_names.each do |attr|
attr = attr.to_sym
address_parts[attr] = params[attr]
normalized.delete(attr)
end
normalized[:address] = address_parts
normalized
end
def update_contact_via_api(uuid)
uri = URI.parse("#{ENV['registrant_api_base_url']}/api/v1/registrant/contacts/#{uuid}")
request = Net::HTTP::Patch.new(uri)
request['Authorization'] = "Bearer #{access_token}"
request['Content-type'] = 'application/json'
request.body = contact_update_api_params.to_json
Net::HTTP.start(uri.hostname, uri.port, use_ssl: (uri.scheme == 'https')) do |http|
http.request(request)
end
end
def domain_filter_params
params.permit(:domain_filter)
end
end

View file

@ -1,44 +0,0 @@
class Registrant::DomainDeleteConfirmsController < RegistrantController
skip_before_action :authenticate_registrant_user!, only: [:show, :update]
skip_authorization_check only: [:show, :update]
def show
return if params[:confirmed] || params[:rejected]
@domain = Domain.find(params[:id])
@domain = nil unless @domain.registrant_delete_confirmable?(params[:token])
end
def update
@domain = Domain.find(params[:id])
unless @domain.registrant_delete_confirmable?(params[:token])
flash[:alert] = t(:registrant_domain_verification_failed)
return render 'show'
end
@registrant_verification = RegistrantVerification.new(domain_id: @domain.id,
verification_token: params[:token])
initiator = current_registrant_user ? current_registrant_user.username :
t(:user_not_authenticated)
confirmed = params[:confirmed] ? true : false
action = if confirmed
@registrant_verification.domain_registrant_delete_confirm!("email link #{initiator}")
else
@registrant_verification.domain_registrant_delete_reject!("email link #{initiator}")
end
fail_msg = t("registrant_domain_delete_#{confirmed ? 'confirmed' : 'rejected'}_failed".to_sym)
success_msg = t("registrant_domain_verification_#{confirmed ? 'confirmed' : 'rejected'}".to_sym)
flash[:alert] = action ? success_msg : fail_msg
(render 'show' && return) unless action
if confirmed
redirect_to registrant_domain_delete_confirm_path(@domain.id, confirmed: true)
else
redirect_to registrant_domain_delete_confirm_path(@domain.id, rejected: true)
end
end
end

View file

@ -1,44 +0,0 @@
class Registrant::DomainUpdateConfirmsController < RegistrantController
skip_before_action :authenticate_registrant_user!, only: %i[show update]
skip_authorization_check only: %i[show update]
def show
return if params[:confirmed] || params[:rejected]
@domain = Domain.find(params[:id])
@domain = nil unless @domain.registrant_update_confirmable?(params[:token])
end
def update
@domain = Domain.find(params[:id])
unless @domain.registrant_update_confirmable?(params[:token])
flash[:alert] = t(:registrant_domain_verification_failed)
return render 'show'
end
@registrant_verification = RegistrantVerification.new(domain_id: @domain.id,
verification_token: params[:token])
initiator = current_registrant_user ? current_registrant_user.username :
t(:user_not_authenticated)
if params[:rejected]
if @registrant_verification.domain_registrant_change_reject!("email link, #{initiator}")
flash[:notice] = t(:registrant_domain_verification_rejected)
redirect_to registrant_domain_update_confirm_path(@domain.id, rejected: true)
else
flash[:alert] = t(:registrant_domain_verification_rejected_failed)
return render 'show'
end
elsif params[:confirmed]
if @registrant_verification.domain_registrant_change_confirm!("email link, #{initiator}")
Dispute.close_by_domain(@domain.name) if @domain.disputed?
flash[:notice] = t(:registrant_domain_verification_confirmed)
redirect_to registrant_domain_update_confirm_path(@domain.id, confirmed: true)
else
flash[:alert] = t(:registrant_domain_verification_confirmed_failed)
return render 'show'
end
end
end
end

View file

@ -1,79 +0,0 @@
class Registrant::DomainsController < RegistrantController
def index
authorize! :view, :registrant_domains
params[:q] ||= {}
normalize_search_parameters do
@q = current_user_domains.search(search_params)
end
domains = @q.result
respond_to do |format|
format.html do
@domains = domains.page(params[:page])
domains_per_page = params[:results_per_page].to_i
@domains = @domains.per(domains_per_page) if domains_per_page.positive?
end
format.csv do
raw_csv = @q.result.to_csv
send_data raw_csv, filename: 'domains.csv', type: "#{Mime[:csv]}; charset=utf-8"
end
format.pdf do
view = ActionView::Base.new(ActionController::Base.view_paths, domains: domains)
raw_html = view.render(file: 'registrant/domains/list_pdf', layout: false)
raw_pdf = domains.pdf(raw_html)
send_data raw_pdf, filename: 'domains.pdf'
end
end
end
def show
@domain = current_user_domains.find(params[:id])
authorize! :read, @domain
end
def confirmation
authorize! :view, :registrant_domains
domain = current_user_domains.find(params[:id])
if (domain.statuses.include?(DomainStatus::PENDING_UPDATE) ||
domain.statuses.include?(DomainStatus::PENDING_DELETE_CONFIRMATION)) &&
domain.pending_json.present?
@domain = domain
@confirmation_url = confirmation_url(domain)
else
flash[:warning] = I18n.t('available_verification_url_not_found')
redirect_to registrant_domain_path(domain)
end
end
private
def normalize_search_parameters
ca_cache = params[:q][:valid_to_lteq]
begin
end_time = params[:q][:valid_to_lteq].try(:to_date)
params[:q][:valid_to_lteq] = end_time.try(:end_of_day)
rescue
logger.warn('Invalid date')
end
yield
params[:q][:valid_to_lteq] = ca_cache
end
def confirmation_url(domain)
if domain.statuses.include?(DomainStatus::PENDING_UPDATE)
registrant_domain_update_confirm_url(token: domain.registrant_verification_token)
elsif domain.statuses.include?(DomainStatus::PENDING_DELETE_CONFIRMATION)
registrant_domain_delete_confirm_url(token: domain.registrant_verification_token)
end
end
def search_params
params.require(:q).permit(:name_matches, :registrant_ident_eq, :valid_to_gteq, :valid_to_lteq,
:results_per_page)
end
end

View file

@ -1,6 +0,0 @@
class Registrant::RegistrarsController < RegistrantController
def show
@registrar = Registrar.find(params[:id])
authorize! :read, @registrar
end
end

View file

@ -1,17 +0,0 @@
class Registrant::SessionsController < Devise::SessionsController
layout 'registrant/application'
private
def after_sign_in_path_for(_resource_or_scope)
registrant_root_path
end
def after_sign_out_path_for(_resource_or_scope)
new_registrant_user_session_path
end
def user_for_paper_trail
current_registrant_user.present? ? current_registrant_user.id_role_username : 'anonymous'
end
end

View file

@ -0,0 +1,18 @@
class Registrar
class AdminContactsController < BulkChangeController
BASE_URL = URI.parse("#{ENV['repp_url']}domains/admin_contacts").freeze
ACTIVE_TAB = :admin_contact
def update
authorize! :manage, :repp
uri = BASE_URL
request = form_request(uri)
response = do_request(request, uri)
start_notice = t('.replaced')
process_response(response: response,
start_notice: start_notice,
active_tab: ACTIVE_TAB)
end
end
end

View file

@ -17,7 +17,7 @@ class Registrar
private
def check_ip_restriction
ip_restriction = Authorization::RestrictedIP.new(request.ip)
ip_restriction = Authorization::RestrictedIp.new(request.ip)
allowed = ip_restriction.can_access_registrar_area?(current_registrar_user.registrar)
return if allowed

View file

@ -26,6 +26,84 @@ class Registrar
private
def form_request(uri)
request = Net::HTTP::Patch.new(uri)
request.set_form_data(current_contact_id: params[:current_contact_id],
new_contact_id: params[:new_contact_id])
request.basic_auth(current_registrar_user.username,
current_registrar_user.plain_text_password)
request
end
def process_response(response:, start_notice: '', active_tab:)
parsed_response = JSON.parse(response.body, symbolize_names: true)
if response.code == '200'
notices = success_notices(parsed_response, start_notice)
flash[:notice] = notices.join(', ')
redirect_to registrar_domains_url
else
@error = response.code == '404' ? 'Contact(s) not found' : parsed_response[:message]
render file: 'registrar/bulk_change/new', locals: { active_tab: active_tab }
end
end
def success_notices(parsed_response, start_notice)
notices = [start_notice]
notices << "#{t('.affected_domains')}: " \
"#{parsed_response[:data][:affected_domains].join(', ')}"
if parsed_response[:data][:skipped_domains]
notices << "#{t('.skipped_domains')}: " \
"#{parsed_response[:data][:skipped_domains].join(', ')}"
end
notices
end
def do_request(request, uri)
response = if Rails.env.test?
do_test_request(request, uri)
elsif Rails.env.development?
do_dev_request(request, uri)
else
do_live_request(request, uri)
end
response
end
def do_live_request(request, uri)
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
end
def do_dev_request(request, uri)
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE,
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
end
def do_test_request(request, uri)
Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
http.request(request)
end
end
def ready_to_renew?
domain_ids_for_bulk_renew.present? && params[:renew].present?
end

View file

@ -25,32 +25,7 @@ class Registrar
current_registrar_user.plain_text_password)
if Rails.env.test?
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
http.request(request)
end
elsif Rails.env.development?
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE,
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
else
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
end
response = do_request(request, uri)
parsed_response = JSON.parse(response.body, symbolize_names: true)

View file

@ -49,7 +49,7 @@ class Registrar
domain_presenters << ::DomainPresenter.new(domain: domain, view: view_context)
end
raw_csv = Registrar::DomainListCSVPresenter.new(domains: domain_presenters,
raw_csv = Registrar::DomainListCsvPresenter.new(domains: domain_presenters,
view: view_context).to_s
filename = "Domains_#{l(Time.zone.now, format: :filename)}.csv"
send_data raw_csv, filename: filename, type: "#{Mime[:csv]}; charset=utf-8"

View file

@ -18,32 +18,7 @@ class Registrar
request.basic_auth(current_registrar_user.username,
current_registrar_user.plain_text_password)
if Rails.env.test?
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
http.request(request)
end
elsif Rails.env.development?
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE,
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
else
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
end
response = do_request(request, uri)
parsed_response = JSON.parse(response.body, symbolize_names: true)

View file

@ -72,7 +72,7 @@ class Registrar
end
def check_ip_restriction
ip_restriction = Authorization::RestrictedIP.new(request.ip)
ip_restriction = Authorization::RestrictedIp.new(request.ip)
allowed = ip_restriction.can_access_registrar_area_sign_in_page?
return if allowed

View file

@ -1,62 +1,19 @@
class Registrar
class TechContactsController < BulkChangeController
BASE_URL = URI.parse("#{ENV['repp_url']}domains/contacts").freeze
ACTIVE_TAB = :technical_contact
def update
authorize! :manage, :repp
uri = URI.parse("#{ENV['repp_url']}domains/contacts")
uri = BASE_URL
request = form_request(uri)
response = do_request(request, uri)
start_notice = t('.replaced')
request = Net::HTTP::Patch.new(uri)
request.set_form_data(current_contact_id: params[:current_contact_id],
new_contact_id: params[:new_contact_id])
request.basic_auth(current_registrar_user.username,
current_registrar_user.plain_text_password)
if Rails.env.test?
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
http.request(request)
end
elsif Rails.env.development?
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE,
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
else
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
end
parsed_response = JSON.parse(response.body, symbolize_names: true)
if response.code == '200'
notices = [t('.replaced')]
notices << "#{t('.affected_domains')}: " \
"#{parsed_response[:data][:affected_domains].join(', ')}"
if parsed_response[:data][:skipped_domains]
notices << "#{t('.skipped_domains')}: " \
"#{parsed_response[:data][:skipped_domains].join(', ')}"
end
flash[:notice] = notices.join(', ')
redirect_to registrar_domains_url
else
@error = response.code == '404' ? 'Contact(s) not found' : parsed_response[:message]
render file: 'registrar/bulk_change/new', locals: { active_tab: :technical_contact }
end
process_response(response: response,
start_notice: start_notice,
active_tab: ACTIVE_TAB)
end
end
end

View file

@ -4,8 +4,28 @@ module Repp
def balance
resp = { balance: current_user.registrar.cash_account.balance,
currency: current_user.registrar.cash_account.currency }
resp[:transactions] = activities if params[:detailed] == 'true'
render_success(data: resp)
end
def activities
arr = []
registrar_activities.each do |a|
arr << { created_at: a.created_at, description: a.description,
type: a.activity_type == 'add_credit' ? 'credit' : 'debit',
sum: a.sum, balance: a.new_balance }
end
arr
end
def registrar_activities
activities = current_user.registrar.cash_account.activities.order(created_at: :desc)
activities = activities.where('created_at >= ?', params[:from]) if params[:from]
activities = activities.where('created_at <= ?', params[:until]) if params[:until]
activities
end
end
end
end

View file

@ -0,0 +1,21 @@
module Repp
module V1
module Domains
class AdminContactsController < BaseContactsController
def update
super
unless @new_contact.identical_to?(@current_contact)
@epp_errors << { code: 2304, msg: 'Admin contacts must be identical' }
end
return handle_errors if @epp_errors.any?
affected, skipped = AdminDomainContact.replace(@current_contact, @new_contact)
@response = { affected_domains: affected, skipped_domains: skipped }
render_success(data: @response)
end
end
end
end
end

View file

@ -0,0 +1,31 @@
module Repp
module V1
module Domains
class BaseContactsController < BaseController
before_action :set_current_contact, only: [:update]
before_action :set_new_contact, only: [:update]
def set_current_contact
@current_contact = current_user.registrar.contacts
.find_by!(code: contact_params[:current_contact_id])
end
def set_new_contact
@new_contact = current_user.registrar.contacts.find_by!(code: params[:new_contact_id])
end
def update
@epp_errors ||= []
@epp_errors << { code: 2304, msg: 'New contact must be valid' } if @new_contact.invalid?
end
private
def contact_params
params.require(%i[current_contact_id new_contact_id])
params.permit(:current_contact_id, :new_contact_id)
end
end
end
end
end

View file

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

View file

@ -14,7 +14,7 @@ module Sso
# rubocop:disable Style/AndOr
def callback(user, registrar: true)
session[:omniauth_hash] = user_hash
session[:omniauth_hash] = user_hash.delete_if { |key, _| key == 'credentials' }
(show_error(registrar: registrar) and return) unless user
flash[:notice] = t(:signed_in_successfully)

View file

@ -17,7 +17,9 @@ module Domains
def notify_pending_update
RegistrantChangeMailer.expired(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant).deliver_later
registrant: domain.registrant,
send_to: [domain.new_registrant_email,
domain.registrant.email]).deliver_later
end
def notify_pending_delete

View file

@ -1,20 +0,0 @@
class RegistrantChangeExpiredEmailJob < Que::Job
def run(domain_id)
domain = Domain.find(domain_id)
log(domain)
RegistrantChangeMailer.expired(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant).deliver_now
end
private
def log(domain)
message = "Send RegistrantChangeMailer#expired email for domain #{domain.name} (##{domain.id}) to #{domain.new_registrant_email}"
logger.info(message)
end
def logger
Rails.logger
end
end

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

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

View file

@ -6,10 +6,6 @@ class ApplicationMailer < ActionMailer::Base
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

@ -1,4 +1,4 @@
class PunycodeInterceptor
class Interceptors::PunycodeInterceptor
class << self
def delivering_email(message)
message.from = encode_addresses_as_punycode(message.from)

View file

@ -38,13 +38,13 @@ class RegistrantChangeMailer < ApplicationMailer
mail(to: domain.new_registrant_email, subject: subject)
end
def expired(domain:, registrar:, registrant:)
def expired(domain:, registrar:, registrant:, send_to:)
@domain = DomainPresenter.new(domain: domain, view: view_context)
@registrar = RegistrarPresenter.new(registrar: registrar, view: view_context)
@registrant = RegistrantPresenter.new(registrant: registrant, view: view_context)
subject = default_i18n_subject(domain_name: domain.name)
mail(to: domain.new_registrant_email, subject: subject)
mail(to: send_to, subject: subject)
end
private

View file

@ -89,8 +89,8 @@ class Ability
can :manage, BlockedDomain
can :manage, ReservedDomain
can :manage, DNS::Zone
can :manage, DomainVersion
can :manage, ContactVersion
can :manage, Version::DomainVersion
can :manage, Version::ContactVersion
can :manage, Billing::Price
can :manage, User
can :manage, ApiUser

View file

@ -13,6 +13,9 @@ class AccountActivity < ApplicationRecord
def update_balance
account.balance += sum
account.save
self.new_balance = account.balance
save
end
class << self

View file

@ -1,5 +1,5 @@
class Action < ApplicationRecord
has_paper_trail versions: { class_name: 'ActionVersion' }
has_paper_trail versions: { class_name: 'Version::ActionVersion' }
belongs_to :user
belongs_to :contact

View file

@ -19,6 +19,11 @@ module Actions
return
end
if contact.delete_prohibited?
contact.errors.add(:statuses, :delete_prohibited)
return
end
commit
end

View file

@ -1,2 +1,26 @@
class AdminDomainContact < DomainContact
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def self.replace(current_contact, new_contact)
affected_domains = []
skipped_domains = []
admin_contacts = where(contact: current_contact)
admin_contacts.each do |admin_contact|
if admin_contact.domain.bulk_update_prohibited?
skipped_domains << admin_contact.domain.name
next
end
begin
admin_contact.contact = new_contact
admin_contact.save!
affected_domains << admin_contact.domain.name
rescue ActiveRecord::RecordNotUnique
skipped_domains << admin_contact.domain.name
end
end
[affected_domains.sort, skipped_domains.sort]
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength
end

View file

@ -1,5 +1,5 @@
module Authorization
class RestrictedIP
class RestrictedIp
def initialize(ip)
@ip = ip
end

View file

@ -1,6 +1,6 @@
module Billing
class Price < ApplicationRecord
include Concerns::Billing::Price::Expirable
include Billing::Price::Expirable
include Versions
belongs_to :zone, class_name: 'DNS::Zone', required: true

View file

@ -1,5 +1,6 @@
class BouncedMailAddress < ApplicationRecord
validates :email, :message_id, :bounce_type, :bounce_subtype, :action, :status, presence: true
after_destroy :destroy_aws_suppression
def bounce_reason
"#{action} (#{status} #{diagnostic})"
@ -25,4 +26,20 @@ class BouncedMailAddress < ApplicationRecord
diagnostic: bounced_record['diagnosticCode'],
}
end
def destroy_aws_suppression
return unless BouncedMailAddress.ses_configured?
res = Aws::SESV2::Client.new.delete_suppressed_destination(email_address: email)
res.successful?
rescue Aws::SESV2::Errors::ServiceError => e
logger.warn("Suppression not removed. #{e}")
end
def self.ses_configured?
ses ||= Aws::SESV2::Client.new
ses.config.credentials.access_key_id.present?
rescue Aws::Errors::MissingRegionError
false
end
end

View file

@ -1,4 +1,4 @@
module Concerns::Billing::Price::Expirable
module Billing::Price::Expirable
extend ActiveSupport::Concern
class_methods do

View file

@ -1,6 +1,4 @@
module Concerns
module Contact
module Archivable
module Contact::Archivable
extend ActiveSupport::Concern
class_methods do
@ -37,11 +35,11 @@ module Concerns
end
def inactive?
if DomainVersion.contact_unlinked_more_than?(contact_id: id, period: inactivity_period)
if Version::DomainVersion.contact_unlinked_more_than?(contact_id: id, period: inactivity_period)
return true
end
DomainVersion.was_contact_linked?(id) ? false : created_at <= inactivity_period.ago
Version::DomainVersion.was_contact_linked?(id) ? false : created_at <= inactivity_period.ago
end
def inactivity_period
@ -64,5 +62,3 @@ module Concerns
f.close
end
end
end
end

View file

@ -1,6 +1,4 @@
module Concerns
module Contact
module Disclosable
module Contact::Disclosable
extend ActiveSupport::Concern
class_methods do
@ -22,5 +20,3 @@ module Concerns
errors.add(:disclosed_attributes, :invalid) if has_undisclosable_attributes
end
end
end
end

View file

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

View file

@ -1,4 +1,4 @@
module Concerns::Domain::Activatable
module Domain::Activatable
extend ActiveSupport::Concern
def active?

View file

@ -0,0 +1,13 @@
module Domain::BulkUpdatable
extend ActiveSupport::Concern
def bulk_update_prohibited?
discarded? || statuses_blocks_update?
end
def statuses_blocks_update?
prohibited_array = [DomainStatus::SERVER_UPDATE_PROHIBITED,
DomainStatus::CLIENT_UPDATE_PROHIBITED]
prohibited_array.any? { |block_status| statuses.include?(block_status) }
end
end

View file

@ -1,6 +1,12 @@
module Concerns::Domain::Deletable
module Domain::Deletable
extend ActiveSupport::Concern
DELETE_STATUSES = [
DomainStatus::PENDING_DELETE_CONFIRMATION,
DomainStatus::PENDING_DELETE,
DomainStatus::FORCE_DELETE,
].freeze
private
def delete_later

View file

@ -1,4 +1,4 @@
module Concerns::Domain::Discardable
module Domain::Discardable
extend ActiveSupport::Concern
def keep

View file

@ -1,8 +1,6 @@
# frozen_string_literal: true
module Concerns
module Domain
module Disputable
module Domain::Disputable
extend ActiveSupport::Concern
included do
@ -40,5 +38,3 @@ module Concerns
errors.add(:base, :invalid_auth_information_reserved)
end
end
end
end

View file

@ -1,4 +1,4 @@
module Concerns::Domain::Expirable
module Domain::Expirable
extend ActiveSupport::Concern
included do

View file

@ -1,4 +1,4 @@
module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength
module Domain::ForceDelete # rubocop:disable Metrics/ModuleLength
extend ActiveSupport::Concern
included do
@ -11,6 +11,11 @@ module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength
lambda {
where("(force_delete_data->>'contact_notification_sent_date') is null")
}
HOLD_STATUSES = [
DomainStatus::SERVER_HOLD,
DomainStatus::CLIENT_HOLD,
].freeze
end
class_methods do
@ -19,6 +24,10 @@ module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength
end
end
def hold_status?
HOLD_STATUSES.any? { |status| statuses.include? status }
end
def notification_template(explicit: nil)
reason = explicit&.downcase
return reason if %w[invalid_email invalid_phone].include?(reason)

View file

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

View file

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

View file

@ -1,4 +1,4 @@
module Concerns::Domain::Transferable
module Domain::Transferable
extend ActiveSupport::Concern
included do
@ -31,7 +31,9 @@ module Concerns::Domain::Transferable
DomainStatus::PENDING_TRANSFER,
DomainStatus::FORCE_DELETE,
DomainStatus::SERVER_TRANSFER_PROHIBITED,
DomainStatus::CLIENT_TRANSFER_PROHIBITED
DomainStatus::CLIENT_TRANSFER_PROHIBITED,
DomainStatus::SERVER_UPDATE_PROHIBITED,
DomainStatus::CLIENT_UPDATE_PROHIBITED,
]).empty?
end
@ -59,7 +61,7 @@ module Concerns::Domain::Transferable
copied_ids = []
domain_contacts.each do |dc|
contact = Contact.find(dc.contact_id)
next if copied_ids.include?(contact.id) || contact.registrar == new_registrar
next if copied_ids.include?(uniq_contact_hash(dc)) || contact.registrar == new_registrar
if registrant_id_was == contact.id # registrant was copied previously, do not copy it again
oc = OpenStruct.new(id: registrant_id)
@ -72,7 +74,11 @@ module Concerns::Domain::Transferable
else
dc.update(contact_id: oc.id)
end
copied_ids << contact.id
copied_ids << uniq_contact_hash(dc)
end
end
def uniq_contact_hash(contact)
Digest::SHA1.hexdigest(contact.contact_id.to_s + contact.type)
end
end

View file

@ -1,4 +1,3 @@
module Concerns
module EmailVerifable
extend ActiveSupport::Concern
@ -92,4 +91,3 @@ module Concerns
end
# rubocop:enable Metrics/LineLength
end
end

View file

@ -1,6 +1,4 @@
module Concerns
module Invoice
module BookKeeping
module Invoice::BookKeeping
extend ActiveSupport::Concern
def as_directo_json
@ -30,5 +28,3 @@ module Concerns
}.as_json
end
end
end
end

View file

@ -1,6 +1,4 @@
module Concerns
module Invoice
module Cancellable
module Invoice::Cancellable
extend ActiveSupport::Concern
included do
@ -24,5 +22,3 @@ module Concerns
!cancelled?
end
end
end
end

View file

@ -1,6 +1,4 @@
module Concerns
module Invoice
module Payable
module Invoice::Payable
extend ActiveSupport::Concern
included do
@ -24,5 +22,3 @@ module Concerns
!paid?
end
end
end
end

View file

@ -1,6 +1,4 @@
module Concerns
module Registrar
module BookKeeping
module Registrar::BookKeeping
extend ActiveSupport::Concern
DOMAIN_TO_PRODUCT = { 'ee': '01EE', 'com.ee': '02COM', 'pri.ee': '03PRI',
@ -124,5 +122,3 @@ module Concerns
@pricelists[account_activity.price_id] = account_activity.price
end
end
end
end

View file

@ -1,6 +1,4 @@
module Concerns
module Registrar
module LegalDoc
module Registrar::LegalDoc
extend ActiveSupport::Concern
def legaldoc_mandatory?
@ -12,5 +10,3 @@ module Concerns
legaldoc_optout || !setting
end
end
end
end

View file

@ -7,10 +7,10 @@ module Versions
attr_accessor :version_loader
if WITH_CHILDREN.include?(model_name.name)
has_paper_trail versions: { class_name: "#{model_name}Version" },
has_paper_trail versions: { class_name: "Version::#{model_name}Version" },
meta: { children: :children_log }
else
has_paper_trail versions: { class_name: "#{model_name}Version" }
has_paper_trail versions: { class_name: "Version::#{model_name}Version" }
end
# add creator and updator

View file

@ -1,6 +1,4 @@
module Concerns
module Zone
module WhoisQueryable
module Zone::WhoisQueryable
extend ActiveSupport::Concern
included do
@ -70,5 +68,3 @@ module Concerns
vars
end
end
end
end

View file

@ -4,11 +4,11 @@ class Contact < ApplicationRecord
include Versions # version/contact_version.rb
include EppErrors
include UserEvents
include Concerns::Contact::Transferable
include Concerns::Contact::Identical
include Concerns::Contact::Disclosable
include Concerns::Contact::Archivable
include Concerns::EmailVerifable
include Contact::Transferable
include Contact::Identical
include Contact::Disclosable
include Contact::Archivable
include EmailVerifable
belongs_to :original, class_name: self.name
belongs_to :registrar, required: true
@ -360,9 +360,11 @@ class Contact < ApplicationRecord
@desc
end
# Limits returned objects to 11
def related_domains
a = related_domain_descriptions
a.keys.map { |d| { name: d, id: a[d][:id], roles: a[d][:roles] } }
ids = DomainContact.select(:domain_id).where(contact_id: id).limit(11).map(&:domain_id).uniq
res = Domain.where(id: ids).or(Domain.where(registrant_id: id)).select(:name, :uuid).limit(11)
res.pluck(:name, :uuid).map { |name, id| { name: name, id: id } }
end
def status_notes_array=(notes)

View file

@ -1,4 +1,4 @@
module Concerns::Contact::Transferable
module Contact::Transferable
extend ActiveSupport::Concern
included do
@ -9,7 +9,7 @@ module Concerns::Contact::Transferable
def transfer(new_registrar)
return identical(new_registrar) if identical(new_registrar)
new_contact = self.dup
new_contact = dup
new_contact.registrar = new_registrar
new_contact.original = self
new_contact.code = nil

View file

@ -0,0 +1,41 @@
class ContactRequest < ApplicationRecord
establish_connection :"whois_#{Rails.env}"
self.table_name = 'contact_requests'
STATUS_NEW = 'new'.freeze
STATUS_CONFIRMED = 'confirmed'.freeze
STATUS_SENT = 'sent'.freeze
STATUSES = [STATUS_NEW, STATUS_CONFIRMED, STATUS_SENT].freeze
validates :whois_record_id, presence: true
validates :email, presence: true
validates :name, presence: true
validates :status, inclusion: { in: STATUSES }
attr_readonly :secret,
:valid_to
def self.save_record(params)
contact_request = new(params)
contact_request.secret = create_random_secret
contact_request.valid_to = set_valid_to_24_hours_from_now
contact_request.status = STATUS_NEW
contact_request.save!
contact_request
end
def update_record(params)
self.status = params['status'] if params['status']
self.ip_address = params['ip'] if params['ip']
self.message_id = params['ip'] if params['message_id']
save!
end
def self.create_random_secret
SecureRandom.hex(64)
end
def self.set_valid_to_24_hours_from_now
(Time.zone.now + 24.hours)
end
end

View file

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

View file

@ -5,7 +5,7 @@ module DNS
validates :origin, :ttl, :refresh, :retry, :expire, :minimum_ttl, :email, :master_nameserver, presence: true
validates :ttl, :refresh, :retry, :expire, :minimum_ttl, numericality: { only_integer: true }
validates :origin, uniqueness: true
include Concerns::Zone::WhoisQueryable
include ::Zone::WhoisQueryable
before_destroy do
throw(:abort) if used?

View file

@ -1,15 +1,16 @@
class Domain < ApplicationRecord
include UserEvents
include Versions # version/domain_version.rb
include Concerns::Domain::Expirable
include Concerns::Domain::Activatable
include Concerns::Domain::ForceDelete
include Concerns::Domain::Discardable
include Concerns::Domain::Deletable
include Concerns::Domain::Transferable
include Concerns::Domain::RegistryLockable
include Concerns::Domain::Releasable
include Concerns::Domain::Disputable
include Domain::Expirable
include Domain::Activatable
include Domain::ForceDelete
include Domain::Discardable
include Domain::Deletable
include Domain::Transferable
include Domain::RegistryLockable
include Domain::Releasable
include Domain::Disputable
include Domain::BulkUpdatable
attr_accessor :roles
@ -78,7 +79,7 @@ class Domain < ApplicationRecord
true
end
after_commit :update_whois_record, unless: -> { domain_name.at_auction? }
after_commit :update_whois_record
after_create :update_reserved_domains
def update_reserved_domains
@ -106,9 +107,9 @@ class Domain < ApplicationRecord
validate :status_is_consistant
def status_is_consistant
has_error = (statuses.include?(DomainStatus::SERVER_HOLD) && statuses.include?(DomainStatus::SERVER_MANUAL_INZONE))
has_error = (hold_status? && statuses.include?(DomainStatus::SERVER_MANUAL_INZONE))
unless has_error
if (statuses & [DomainStatus::PENDING_DELETE_CONFIRMATION, DomainStatus::PENDING_DELETE, DomainStatus::FORCE_DELETE]).any?
if (statuses & DELETE_STATUSES).any?
has_error = statuses.include? DomainStatus::SERVER_DELETE_PROHIBITED
end
end
@ -197,6 +198,23 @@ class Domain < ApplicationRecord
Setting.nameserver_required
end
def registrant_user_admin_registrant_domains(registrant_user)
companies = Contact.registrant_user_company_contacts(registrant_user)
from(
"(#{registrant_user_administered_domains(registrant_user).to_sql} UNION " \
"#{registrant_user_company_registrant(companies).to_sql} UNION " \
"#{registrant_user_domains_company(companies, except_tech: true).to_sql}) AS domains"
)
end
def registrant_user_direct_admin_registrant_domains(registrant_user)
from(
"(#{registrant_user_direct_domains_by_registrant(registrant_user).to_sql} UNION " \
"#{registrant_user_direct_domains_by_contact(registrant_user,
except_tech: true).to_sql}) AS domains"
)
end
def registrant_user_domains(registrant_user)
from(
"(#{registrant_user_domains_by_registrant(registrant_user).to_sql} UNION " \
@ -246,16 +264,20 @@ class Domain < ApplicationRecord
where(registrant: registrant_user.direct_contacts)
end
def registrant_user_direct_domains_by_contact(registrant_user)
joins(:domain_contacts).where(domain_contacts: { contact_id: registrant_user.direct_contacts })
def registrant_user_direct_domains_by_contact(registrant_user, except_tech: false)
request = { contact_id: registrant_user.direct_contacts }
request[:type] = [AdminDomainContact.name] if except_tech
joins(:domain_contacts).where(domain_contacts: request)
end
def registrant_user_company_registrant(companies)
where(registrant: companies)
end
def registrant_user_domains_company(companies)
joins(:domain_contacts).where(domain_contacts: { contact: companies })
def registrant_user_domains_company(companies, except_tech: false)
request = { contact: companies }
request[:type] = [AdminDomainContact.name] if except_tech
joins(:domain_contacts).where(domain_contacts: request)
end
end

View file

@ -109,14 +109,12 @@ class DomainStatus < ApplicationRecord
DELETE_PROHIBIT_STATES = [
DomainStatus::CLIENT_DELETE_PROHIBITED,
DomainStatus::SERVER_DELETE_PROHIBITED,
DomainStatus::CLIENT_UPDATE_PROHIBITED,
DomainStatus::SERVER_UPDATE_PROHIBITED,
DomainStatus::PENDING_CREATE,
DomainStatus::PENDING_RENEW,
DomainStatus::PENDING_TRANSFER,
DomainStatus::PENDING_UPDATE,
DomainStatus::PENDING_DELETE
]
].freeze
def epp_code_map
{

View file

@ -42,17 +42,12 @@ class Epp::Contact < Contact
)
end
def check_availability(codes)
def check_availability(codes, reg:)
codes = [codes] if codes.is_a?(String)
res = []
codes.each do |x|
contact = find_by_epp_code(x)
if contact
res << { code: contact.code, avail: 0, reason: 'in use' }
else
res << { code: x, avail: 1 }
end
codes.map { |c| c.include?(':') ? c : "#{reg}:#{c}" }.map { |c| c.strip.upcase }.each do |x|
c = find_by_epp_code(x)
res << (c ? { code: c.code, avail: 0, reason: 'in use' } : { code: x, avail: 1 })
end
res
@ -87,8 +82,11 @@ class Epp::Contact < Contact
'2302' => [ # Object exists
[:code, :epp_id_taken]
],
'2304' => [ # Status prohibits operation
[:statuses, :delete_prohibited],
],
'2305' => [ # Association exists
[:domains, :exist]
[:domains, :exist],
]
}
end

View file

@ -162,6 +162,9 @@ class Epp::Domain < Domain
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?
@ -176,6 +179,11 @@ class Epp::Domain < Domain
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
@ -312,6 +320,7 @@ class Epp::Domain < Domain
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'
@ -333,6 +342,16 @@ class Epp::Domain < Domain
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 = []
@ -446,7 +465,7 @@ class Epp::Domain < Domain
def update(frame, current_user, verify = true)
return super if frame.blank?
if discarded?
if discarded? || statuses_blocks_update?
add_epp_error('2304', nil, nil, 'Object status prohibits operation')
return
end
@ -476,7 +495,7 @@ class Epp::Domain < Domain
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 = (registrant.code != frame.css('registrant').text)
registrant_verification_needed = verification_needed?(code: frame.css('registrant').text)
end
if registrant_verification_needed && disputed?
@ -520,6 +539,7 @@ class Epp::Domain < Domain
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(
@ -592,7 +612,6 @@ class Epp::Domain < Domain
statuses.delete(DomainStatus::SERVER_HOLD)
statuses.delete(DomainStatus::EXPIRED)
statuses.delete(DomainStatus::SERVER_UPDATE_PROHIBITED)
cancel_pending_delete
save
@ -778,4 +797,13 @@ class Epp::Domain < Domain
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

View file

@ -1,8 +1,8 @@
class Invoice < ApplicationRecord
include Versions
include Concerns::Invoice::Cancellable
include Concerns::Invoice::Payable
include Concerns::Invoice::BookKeeping
include Invoice::Cancellable
include Invoice::Payable
include Invoice::BookKeeping
belongs_to :buyer, class_name: 'Registrar'
has_one :account_activity
@ -34,7 +34,7 @@ class Invoice < ApplicationRecord
before_create :calculate_total, unless: :total?
before_create :apply_default_buyer_vat_no, unless: :buyer_vat_no?
attribute :vat_rate, ::Type::VATRate.new
attribute :vat_rate, ::Type::VatRate.new
def set_invoice_number
last_no = Invoice.order(number: :desc).limit(1).pluck(:number).first

View file

@ -82,7 +82,7 @@ class LegalDocument < ApplicationRecord
end
end
contact_ids = DomainVersion.where(item_id: orig_legal.documentable_id).distinct.
contact_ids = Version::DomainVersion.where(item_id: orig_legal.documentable_id).distinct.
pluck("object->>'registrant_id'", "object_changes->>'registrant_id'",
"children->>'tech_contacts'", "children->>'admin_contacts'").flatten.uniq
contact_ids = contact_ids.map{|id|

View file

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

View file

@ -9,7 +9,7 @@ class RegistrantUser < User
delegate :can?, :cannot?, to: :ability
def ident
registrant_ident.to_s.split('-').last
registrant_ident.to_s[3..]
end
def country
@ -18,6 +18,8 @@ class RegistrantUser < User
end
def companies(company_register = CompanyRegister::Client.new)
return [] if ident.include?('-')
company_register.representation_rights(citizen_personal_code: ident,
citizen_country_code: country.alpha3)
end
@ -30,11 +32,15 @@ class RegistrantUser < User
Contact.registrant_user_direct_contacts(self)
end
def domains
def domains(admin: false)
return Domain.registrant_user_admin_registrant_domains(self) if admin
Domain.registrant_user_domains(self)
end
def direct_domains
def direct_domains(admin: false)
return Domain.registrant_user_direct_admin_registrant_domains(self) if admin
Domain.registrant_user_direct_domains(self)
end
@ -72,7 +78,7 @@ class RegistrantUser < User
return false unless user_data[:last_name]
user_data[:country_code] ||= 'EE'
%i[ident country_code].each { |f| user_data[f].upcase! if user_data[f].is_a?(String) }
user_data[:country_code].upcase! if user_data[:country_code].is_a?(String)
find_or_create_by_user_data(user_data)
end

View file

@ -1,8 +1,8 @@
class Registrar < ApplicationRecord
include Versions # version/registrar_version.rb
include Concerns::Registrar::BookKeeping
include Concerns::EmailVerifable
include Concerns::Registrar::LegalDoc
include Registrar::BookKeeping
include EmailVerifable
include Registrar::LegalDoc
has_many :domains, dependent: :restrict_with_error
has_many :contacts, dependent: :restrict_with_error
@ -30,7 +30,7 @@ class Registrar < ApplicationRecord
validates :vat_rate, numericality: { greater_than_or_equal_to: 0, less_than: 100 },
allow_nil: true
attribute :vat_rate, ::Type::VATRate.new
attribute :vat_rate, ::Type::VatRate.new
after_initialize :set_defaults
validate :correct_email_format, if: proc { |c| c.will_save_change_to_email? }
@ -153,7 +153,7 @@ class Registrar < ApplicationRecord
puny = origin.domain.name_puny
next unless domains.include?(idn) || domains.include?(puny) || domains.empty?
if origin.domain.nameservers.where(hostname: new_attributes[:hostname]).any?
if domain_not_updatable?(hostname: new_attributes[:hostname], domain: origin.domain)
failed_list << idn
next
end
@ -202,6 +202,10 @@ class Registrar < ApplicationRecord
private
def domain_not_updatable?(hostname:, domain:)
domain.nameservers.where(hostname: hostname).any? || domain.bulk_update_prohibited?
end
def set_defaults
self.language = Setting.default_language unless language
end

View file

@ -6,7 +6,7 @@ class TechDomainContact < DomainContact
tech_contacts = where(contact: current_contact)
tech_contacts.each do |tech_contact|
if tech_contact.domain.discarded?
if tech_contact.domain.bulk_update_prohibited?
skipped_domains << tech_contact.domain.name
next
end
@ -18,7 +18,6 @@ class TechDomainContact < DomainContact
skipped_domains << tech_contact.domain.name
end
end
[affected_domains.sort, skipped_domains.sort]
end
end

View file

@ -1,5 +1,5 @@
module Type
class VATRate < ActiveRecord::Type::Decimal
class VatRate < ActiveRecord::Type::Decimal
def deserialize(value)
super * 100 if value
end

1
app/models/version.rb Normal file
View file

@ -0,0 +1 @@
class Version; end

View file

@ -1,4 +1,4 @@
class AccountActivityVersion < PaperTrail::Version
class Version::AccountActivityVersion < PaperTrail::Version
self.table_name = :log_account_activities
self.sequence_name = :log_account_activities_id_seq
end

View file

@ -1,4 +1,4 @@
class AccountVersion < PaperTrail::Version
class Version::AccountVersion < PaperTrail::Version
self.table_name = :log_accounts
self.sequence_name = :log_accounts_id_seq
end

View file

@ -1,4 +1,4 @@
class ActionVersion < PaperTrail::Version
class Version::ActionVersion < PaperTrail::Version
self.table_name = :log_actions
self.sequence_name = :log_actions_id_seq
end

View file

@ -1,4 +1,4 @@
class BankStatementVersion < PaperTrail::Version
class Version::BankStatementVersion < PaperTrail::Version
self.table_name = :log_bank_statements
self.sequence_name = :log_bank_statements_id_seq
end

View file

@ -1,4 +1,4 @@
class BankTransactionVersion < PaperTrail::Version
class Version::BankTransactionVersion < PaperTrail::Version
self.table_name = :log_bank_transactions
self.sequence_name = :log_bank_transactions_id_seq
end

View file

@ -1,7 +1,4 @@
module Billing
class PriceVersion < PaperTrail::Version
class Version::Billing::PriceVersion < PaperTrail::Version
self.table_name = :log_prices
self.sequence_name = :log_prices_id_seq
end
end

View file

@ -1,4 +1,4 @@
class BlockedDomainVersion < PaperTrail::Version
class Version::BlockedDomainVersion < PaperTrail::Version
self.table_name = :log_blocked_domains
self.sequence_name = :log_blocked_domains_id_seq
end

View file

@ -1,4 +1,4 @@
class CertificateVersion < PaperTrail::Version
class Version::CertificateVersion < PaperTrail::Version
self.table_name = :log_certificates
self.sequence_name = :log_certificates_id_seq
end

View file

@ -1,4 +1,4 @@
class ContactVersion < PaperTrail::Version
class Version::ContactVersion < PaperTrail::Version
include VersionSession
self.table_name = :log_contacts
self.sequence_name = :log_contacts_id_seq

Some files were not shown because too many files have changed in this diff Show more