Merge branch 'master' into monthly-invoices-fix

This commit is contained in:
Sergei Tsõganov 2022-12-01 14:36:20 +02:00 committed by GitHub
commit 3ae24f2f68
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
282 changed files with 2625 additions and 6669 deletions

View file

@ -79,7 +79,7 @@ jobs:
- name: Save coverage
run: ./cc-test-reporter format-coverage --output coverage/codeclimate.${{ matrix.ruby }}.json
- uses: actions/upload-artifact@v3.1.0
- uses: actions/upload-artifact@v3.1.1
with:
name: coverage-${{ matrix.ruby }}
path: coverage/codeclimate.${{ matrix.ruby }}.json
@ -104,7 +104,7 @@ jobs:
- name: Give test coverage reporter executable permissions
run: chmod +x cc-test-reporter
- uses: actions/download-artifact@v3.0.0
- uses: actions/download-artifact@v3.0.1
with:
name: coverage-${{ matrix.ruby }}
path: coverage

View file

@ -1,3 +1,86 @@
01.12.2022
* Fixed empty validation result reason in the logs https://github.com/internetee/registry/issues/2490
* Reduced unnecessary logging from email validation logs https://github.com/internetee/registry/issues/2491
30.11.2022
* Validator for incoming disclosed attributes https://github.com/internetee/registry/issues/2486
* Endpoint for registrar xml console feature https://github.com/internetee/registry/pull/2483
29.11.2022
* Fixed pantom statuse issue in REPP https://github.com/internetee/registry/issues/2470
24.11.2022
* Overwrite feature to SendMonthlyInvoicesJob https://github.com/internetee/registry/pull/2485
23.11.2022
* outzone rake task for invalid email domains by @OlegPhenomenon in https://github.com/internetee/registry/pull/2437
* Update dependency paper_trail to v13 by @renovate in https://github.com/internetee/registry/pull/2419
* Bump omniauth from 1.9.1 to 1.9.2 by @dependabot in https://github.com/internetee/registry/pull/2429
* Update dependency pdfkit to v0.8.7.2 [SECURITY] by @renovate in https://github.com/internetee/registry/pull/2472
* Bump google-protobuf from 3.19.4 to 3.21.9 by @dependabot in https://github.com/internetee/registry/pull/2477
* Fix domain contacts repp by @maricavor in https://github.com/internetee/registry/pull/2475
* Update dependency pg to v1.4.5 by @renovate in https://github.com/internetee/registry/pull/2481
* Fixed dates for yearly domains in monthly invoices by @maricavor in https://github.com/internetee/registry/pull/2482
02.11.2022
* outzone rake task for invalid email domains by @OlegPhenomenon in https://github.com/internetee/registry/pull/2437
28.10.2022
* Add request throttling by @yulgolem in https://github.com/internetee/registry/pull/2028
26.10.2022
* Update actions/download-artifact action to v3.0.1 by @renovate in https://github.com/internetee/registry/pull/2464
* Update actions/upload-artifact action to v3.1.1 by @renovate in https://github.com/internetee/registry/pull/2465
* assign the limit of validation records by @OlegPhenomenon in https://github.com/internetee/registry/pull/2466
20.10.2022
* added exception for auctions with no-bids and registred-domains statuses by @OlegPhenomenon in https://github.com/internetee/registry/pull/2403
* assign auction type for nil value rake task by @OlegPhenomenon in https://github.com/internetee/registry/pull/2404
17.10.2022
* Remove registrar portal by @thiagoyoussef in https://github.com/internetee/registry/pull/2434
* Update dependency pg to v1.4.4 by @renovate in https://github.com/internetee/registry/pull/2459
* fix check force delete lift poll messages by @thiagoyoussef in https://github.com/internetee/registry/pull/2461
12.10.2022
* Created regex only email validation domain list by @maricavor in https://github.com/internetee/registry/pull/2401
* Fix check force delete lift bug by @thiagoyoussef in https://github.com/internetee/registry/pull/2418
* Refactored monthly invoice generation job by @maricavor in https://github.com/internetee/registry/pull/2456
07.10.2022
* Enable trimming for dnskey and email values by @thiagoyoussef in https://github.com/internetee/registry/pull/2453
06.10.2022
* Update dependency pdfkit to v0.8.7 [SECURITY] by @renovate in https://github.com/internetee/registry/pull/2452
* Admin: option to delete auction record by @thiagoyoussef in https://github.com/internetee/registry/pull/2449
* Add monthly invoice email description by @thiagoyoussef in https://github.com/internetee/registry/pull/2442
03.10.2022
* fixed zeitwerk load file issue by @OlegPhenomenon in https://github.com/internetee/registry/pull/2448
* added sidekiq link to admin view by @OlegPhenomenon in https://github.com/internetee/registry/pull/2447
* protected public method account activity create by @OlegPhenomenon in https://github.com/internetee/registry/pull/2443
29.09.2022
* Update dependency haml to v6 by @renovate in https://github.com/internetee/registry/pull/2444
* added endpoints to demo registry for accr results by @OlegPhenomenon in https://github.com/internetee/registry/pull/2237
* Refactor: remove legacy que by @thiagoyoussef in https://github.com/internetee/registry/pull/2337
* fixed type of auction for next rounds by @OlegPhenomenon in https://github.com/internetee/registry/pull/2393
* Admin: download pdf with domain data on show by @thiagoyoussef in https://github.com/internetee/registry/pull/2396
* Increase notification text field length on database by @thiagoyoussef in https://github.com/internetee/registry/pull/2397
20.09.2022
* Created market share chart data endpoint by @maricavor in https://github.com/internetee/registry/pull/2426
16.09.2022
* Removed 200 limit of records if nil by @maricavor in https://github.com/internetee/registry/pull/2440
* fixed legal doc issue output by @OlegPhenomenon in https://github.com/internetee/registry/pull/2410
* extended csv domain export by @OlegPhenomenon in https://github.com/internetee/registry/pull/2407
* remove fixed top registrar navbar css class by @OlegPhenomenon in https://github.com/internetee/registry/pull/2406
13.09.2022
* Ignore statuses update if invoice already paid by @OlegPhenomenon in https://github.com/internetee/registry/pull/2438
* remove eis-billing feature toggle by @OlegPhenomenon in https://github.com/internetee/registry/pull/2433
08.09.2022
* Fixed template error for multi-year registered domains in force delete process [#2435](https://github.com/internetee/registry/issues/2435)

14
Gemfile
View file

@ -16,8 +16,8 @@ gem 'uglifier'
gem 'figaro', '~> 1.2'
# model related
gem 'paper_trail', '~> 12.1'
gem 'pg', '1.4.3'
gem 'paper_trail', '~> 13.0'
gem 'pg', '1.4.5'
# 1.8 is for Rails < 5.0
gem 'ransack', '~> 2.6.0'
gem 'truemail', '~> 2.4' # validates email by regexp, mail server existence and address existence
@ -30,13 +30,12 @@ gem 'nokogiri', '~> 1.13.0'
# style
gem 'bootstrap-sass', '~> 3.4'
gem 'cancancan'
gem 'coderay', '1.1.3' # xml console visualize
gem 'coffee-rails', '>= 5.0'
gem 'devise', '~> 4.8'
gem 'jquery-rails'
gem 'kaminari'
gem 'sass-rails'
gem 'select2-rails', '4.0.13' # for autocomplete
gem 'select2-rails', '4.0.13' # for autocomplete
gem 'selectize-rails', '0.12.6' # include selectize.js for select
# registry specfic
@ -48,7 +47,7 @@ gem 'simpleidn', '0.2.1' # For punycode
gem 'whenever', '1.0.0', require: false
# country listing
gem 'countries', :require => 'countries/global'
gem 'countries', require: 'countries/global'
# id + mid login
# gem 'digidoc_client', '0.3.0'
@ -77,7 +76,6 @@ gem 'lhv', github: 'internetee/lhv', branch: 'master'
gem 'rexml'
gem 'wkhtmltopdf-binary', '~> 0.12.5.1'
gem 'directo', github: 'internetee/directo', branch: 'master'
group :development, :test do
@ -95,12 +93,12 @@ group :test do
end
gem 'aws-sdk-sesv2', '~> 1.19'
gem 'newrelic-infinite_tracing'
gem 'newrelic_rpm'
# profiles
gem 'pghero'
gem 'pg_query', '>= 0.9.0'
gem 'newrelic_rpm'
gem 'newrelic-infinite_tracing'
# token
gem 'jwt'

View file

@ -55,11 +55,11 @@ GIT
GIT
remote: https://github.com/internetee/omniauth-tara.git
revision: cec845ec3794532144c4976104a07e206d759aa6
revision: 215f5e91b8c1a51b2fe9a72755585096252a2f93
specs:
omniauth-tara (0.3.0)
omniauth-tara (0.4.0)
addressable (~> 2.5)
omniauth (~> 1.3)
omniauth (>= 1.9, < 3)
openid_connect (~> 1.1)
GIT
@ -139,8 +139,8 @@ GEM
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
addressable (2.8.1)
public_suffix (>= 2.0.2, < 6.0)
aes_key_wrap (1.1.0)
airbrake (11.0.3)
airbrake-ruby (~> 5.1)
@ -168,7 +168,7 @@ GEM
aws-sigv4 (1.2.4)
aws-eventstream (~> 1, >= 1.0.2)
bcrypt (3.1.16)
bindata (2.4.10)
bindata (2.4.14)
bootsnap (1.9.3)
msgpack (~> 1.0)
bootstrap-sass (3.4.1)
@ -224,13 +224,19 @@ GEM
unf (>= 0.0.5, < 1.0.0)
erubi (1.10.0)
execjs (2.7.0)
faraday (2.6.0)
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-follow_redirects (0.3.0)
faraday (>= 1, < 3)
faraday-net_http (3.0.1)
ffi (1.15.0)
figaro (1.2.0)
thor (>= 0.14.0, < 2)
globalid (0.5.2)
activesupport (>= 5.0)
google-protobuf (3.19.4)
google-protobuf (3.19.4-x86_64-linux)
google-protobuf (3.21.9)
google-protobuf (3.21.9-x86_64-linux)
googleapis-common-protos-types (1.3.0)
google-protobuf (~> 3.14)
grpc (1.41.1)
@ -246,7 +252,7 @@ GEM
thor
tilt
hashdiff (1.0.1)
hashie (4.1.0)
hashie (5.0.0)
hpricot (0.8.6)
http-accept (1.7.0)
http-cookie (1.0.3)
@ -268,10 +274,12 @@ GEM
jquery-ui-rails (6.0.1)
railties (>= 3.2.16)
json (2.5.1)
json-jwt (1.13.0)
json-jwt (1.16.1)
activesupport (>= 4.2)
aes_key_wrap
bindata
faraday (~> 2.0)
faraday-follow_redirects
jwt (2.3.0)
kaminari (1.2.1)
activesupport (>= 4.1.0)
@ -300,9 +308,9 @@ GEM
mimemagic (0.4.3)
nokogiri (~> 1)
rake
mini_mime (1.1.1)
mini_mime (1.1.2)
mini_portile2 (2.8.0)
minitest (5.15.0)
minitest (5.16.3)
monetize (1.9.4)
money (~> 6.12)
money (6.13.8)
@ -313,40 +321,46 @@ GEM
money (~> 6.13.2)
railties (>= 3.0)
msgpack (1.4.2)
net-protocol (0.1.3)
timeout
net-smtp (0.3.3)
net-protocol
netrc (0.11.0)
newrelic-infinite_tracing (8.1.0)
grpc (~> 1.34)
newrelic_rpm (= 8.1.0)
newrelic_rpm (8.1.0)
nio4r (2.5.8)
nokogiri (1.13.6)
nokogiri (1.13.9)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
nokogiri (1.13.6-x86_64-linux)
nokogiri (1.13.9-x86_64-linux)
racc (~> 1.4)
nori (2.6.0)
omniauth (1.9.1)
omniauth (2.1.0)
hashie (>= 3.4.6)
rack (>= 1.6.2, < 3)
rack (>= 2.2.3)
rack-protection
omniauth-rails_csrf_protection (0.1.2)
actionpack (>= 4.2)
omniauth (>= 1.3.1)
openid_connect (1.3.0)
openid_connect (1.4.2)
activemodel
attr_required (>= 1.0.0)
json-jwt (>= 1.5.0)
rack-oauth2 (>= 1.6.1)
swd (>= 1.0.0)
json-jwt (>= 1.15.0)
net-smtp
rack-oauth2 (~> 1.21)
swd (~> 1.3)
tzinfo
validate_email
validate_url
webfinger (>= 1.0.1)
webfinger (~> 1.2)
orm_adapter (0.5.0)
paper_trail (12.1.0)
paper_trail (13.0.0)
activerecord (>= 5.2)
request_store (~> 1.1)
pdfkit (0.8.7)
pg (1.4.3)
pdfkit (0.8.7.2)
pg (1.4.5)
pg_query (2.1.2)
google-protobuf (>= 3.17.1)
pghero (2.8.1)
@ -354,17 +368,19 @@ GEM
pry (0.14.1)
coderay (~> 1.1)
method_source (~> 1.0)
public_suffix (4.0.6)
public_suffix (5.0.0)
puma (5.6.4)
nio4r (~> 2.0)
racc (1.6.0)
rack (2.2.4)
rack-oauth2 (1.16.0)
rack-oauth2 (1.21.3)
activesupport
attr_required
httpclient
json-jwt (>= 1.11.0)
rack (>= 2.1.0)
rack-protection (3.0.2)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (6.1.4.1)
@ -401,7 +417,7 @@ GEM
rbtree3 (0.6.0)
redis (4.6.0)
regexp_parser (2.1.1)
request_store (1.5.0)
request_store (1.5.1)
rack (>= 1.4)
responders (3.0.1)
actionpack (>= 5.0)
@ -412,6 +428,7 @@ GEM
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
rexml (3.2.5)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
sass-rails (6.0.0)
sassc-rails (~> 2.1, >= 2.1.1)
@ -464,9 +481,10 @@ GEM
temple (0.8.2)
thor (1.2.1)
tilt (2.0.11)
timeout (0.3.0)
truemail (2.4.9)
simpleidn (~> 0.2.1)
tzinfo (2.0.4)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
@ -506,7 +524,7 @@ GEM
wkhtmltopdf-binary (0.12.5.4)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.5.4)
zeitwerk (2.6.6)
PLATFORMS
ruby
@ -521,7 +539,6 @@ DEPENDENCIES
bootstrap-sass (~> 3.4)
cancancan
capybara
coderay (= 1.1.3)
coffee-rails (>= 5.0)
company_register!
countries
@ -553,9 +570,9 @@ DEPENDENCIES
nokogiri (~> 1.13.0)
omniauth-rails_csrf_protection
omniauth-tara!
paper_trail (~> 12.1)
paper_trail (~> 13.0)
pdfkit
pg (= 1.4.3)
pg (= 1.4.5)
pg_query (>= 0.9.0)
pghero
pry (= 0.14.1)
@ -580,4 +597,4 @@ DEPENDENCIES
wkhtmltopdf-binary (~> 0.12.5.1)
BUNDLED WITH
2.3.21
2.3.25

View file

@ -31,7 +31,7 @@ module Admin
def create
auction = Auction.new(domain: params[:domain], status: Auction.statuses[:started], platform: 'manual')
if domain_exists_in_blocked_disputed_and_registered?(params[:domain])
if Auction.domain_exists_in_blocked_disputed_and_registered?(params[:domain])
flash[:alert] = "Adding #{params[:domain]} failed - domain registered or regsitration is blocked"
redirect_to admin_auctions_path and return
end
@ -81,7 +81,7 @@ module Admin
table.each do |row|
record = row.to_h
if domain_exists_in_blocked_disputed_and_registered?(record['name'])
if Auction.domain_exists_in_blocked_disputed_and_registered?(record['name'])
failed_names << record['name']
next
@ -119,13 +119,6 @@ module Admin
Epp::Domain.check_availability(domain_name)
end
def domain_exists_in_blocked_disputed_and_registered?(domain_name)
Domain.exists?(name: domain_name) ||
BlockedDomain.exists?(name: domain_name) ||
Dispute.exists?(domain_name: domain_name) ||
Auction.exists?(domain: domain_name)
end
def validate_table(table)
first_row = table.headers
first_row.include? 'name'

View file

@ -3,7 +3,6 @@ module Api
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?
@ -19,6 +18,8 @@ module Api
process_id(params[:id])
end
private
def process_id(id)
record = ContactRequest.find_by(id: id)
return :not_found unless record

View file

@ -46,63 +46,36 @@ module Api
end
def update
logger.debug 'Received update request'
logger.debug params
contact = current_user_contacts.find_by!(uuid: params[:uuid])
contact.name = params[:name] if params[:name].present?
contact.email = params[:email] if params[:email].present?
contact.phone = params[:phone] if params[:phone].present?
contact = find_contact_and_update_credentials(params[:uuid], params[:name], params[:email], params[:phone])
reparsed_request = reparsed_request(request.body.string)
disclosed_attributes = reparsed_request[:disclosed_attributes]
# Needed to support passing empty array, which otherwise gets parsed to nil
# https://github.com/rails/rails/pull/13157
reparsed_request_json = ActiveSupport::JSON.decode(request.body.string)
.with_indifferent_access
logger.debug 'Reparsed request is following'
logger.debug reparsed_request_json.to_s
disclosed_attributes = reparsed_request_json[:disclosed_attributes]
if disclosed_attributes
if disclosed_attributes.present? && contact.org?
error_msg = "Legal person's data is visible by default and cannot be concealed." \
' Please remove this parameter.'
render json: { errors: [{ disclosed_attributes: [error_msg] }] }, status: :bad_request
return
end
contact.disclosed_attributes = disclosed_attributes
if disclosed_attributes.present?
extra_attrs = disclosed_attributes - Contact::DISCLOSE_ATTRIBUTES
attributes_not_exist_error(extra_attrs) and return if extra_attrs.present?
end
if disclosed_attributes.present? && contact.org?
extra_attrs = disclosed_attributes - Contact::OPEN_LEGAL_ATTRIBUTES
render_disclosed_attributes_error and return if extra_attrs.present?
end
contact.disclosed_attributes = disclosed_attributes if disclosed_attributes
publishable = reparsed_request[:registrant_publishable]
contact.registrant_publishable = publishable if publishable.in? [true, false]
logger.debug "Setting.address_processing is set to #{Setting.address_processing}"
if Setting.address_processing && params[:address]
address = Contact::Address.new(params[:address][:street],
params[:address][:zip],
params[:address][:city],
params[:address][:state],
params[:address][:country_code])
contact.address = address
end
if !Setting.address_processing && params[:address]
error_msg = 'Address processing is disabled and therefore cannot be updated'
render json: { errors: [{ address: [error_msg] }] }, status: :bad_request and return
end
contact.address = parse_address(params[:address]) if Setting.address_processing && params[:address]
render_address_error and return if !Setting.address_processing && params[:address]
contact.fax = params[:fax] if ENV['fax_enabled'] == 'true' && params[:fax].present?
logger.debug "ENV['fax_enabled'] is set to #{ENV['fax_enabled']}"
if ENV['fax_enabled'] != 'true' && params[:fax]
error_msg = 'Fax processing is disabled and therefore cannot be updated'
render json: { errors: [{ address: [error_msg] }] }, status: :bad_request and return
end
render_fax_error and return if ENV['fax_enabled'] != 'true' && params[:fax]
contact.transaction do
contact.save!
action = current_registrant_user.actions.create!(contact: contact, operation: :update)
contact.registrar.notify(action)
end
contact = update_and_notify!(contact)
render json: serialize_contact(contact, false)
render json: serialize_contact(contact, true)
end
private
@ -136,6 +109,64 @@ module Api
def logger
Rails.logger
end
def render_disclosed_attributes_error
error_msg = "Legal person's data is visible by default and cannot be concealed." \
' Please remove this parameter.'
render json: { errors: [{ disclosed_attributes: [error_msg] }] }, status: :bad_request
end
def parse_address(address)
Contact::Address.new(
address[:street],
address[:zip],
address[:city],
address[:state],
address[:country_code]
)
end
def attributes_not_exist_error(extra_attrs)
error_msg = "Request contains extra attributes: #{extra_attrs.join(', ')}"
render json: { errors: [{ disclosed_attributes: [error_msg] }] }, status: :bad_request
end
def render_address_error
error_msg = 'Address processing is disabled and therefore cannot be updated'
render json: { errors: [{ address: [error_msg] }] }, status: :bad_request
end
def render_fax_error
error_msg = 'Fax processing is disabled and therefore cannot be updated'
render json: { errors: [{ address: [error_msg] }] }, status: :bad_request
end
def update_and_notify!(contact)
contact.transaction do
contact.save!
action = current_registrant_user.actions.create!(contact: contact, operation: :update)
contact.registrar.notify(action)
end
contact
end
def reparsed_request(request_body)
reparsed_request = ActiveSupport::JSON.decode(request_body).with_indifferent_access
logger.debug 'Reparsed request is following'
logger.debug reparsed_request.to_s
reparsed_request
end
def find_contact_and_update_credentials(uuid, name, email, phone)
contact = current_user_contacts.find_by!(uuid: uuid)
contact.name = name if name.present?
contact.email = email if email.present?
contact.phone = phone if phone.present?
contact
end
end
end
end

View file

@ -0,0 +1,63 @@
module EppRequestable
extend ActiveSupport::Concern
included do
# before_action :validate_epp_user, only: :create
end
def create
result = server.request(request_params[:payload])
render_success(data: { xml: result.force_encoding('UTF-8') })
rescue StandardError
handle_non_epp_errors(nil, I18n.t('errors.messages.epp_conn_error'))
end
private
# def validate_epp_user
# return unless handle_hello_request
# handle_login_request
# server.close_connection
# rescue OpenSSL::SSL::SSLError => e
# Rails.logger.error "INVALID CERT: #{e}"
# Rails.logger.error "INVALID CERT DEBUG INFO: epp_hostname: #{ENV['epp_hostname']}," \
# "port: #{ENV['epp_port']}, cert_path: #{ENV['cert_path']}, key_path: #{ENV['key_path']}"
# handle_non_epp_errors(nil, I18n.t('errors.messages.invalid_cert'))
# end
# def handle_hello_request
# res = server.open_connection
# unless Nokogiri::XML(res).css('greeting')
# server.close_connection # just in case
# handle_non_epp_errors(nil, I18n.t('errors.messages.failed_epp_conn')) and return false
# end
# true
# end
# def handle_login_request
# tag = current_user.username
# ex = EppXml::Session.new(cl_trid_prefix: tag)
# xml = ex.login(clID: { value: tag }, pw: { value: current_user.plain_text_password })
# res = server.send_request(xml)
# return if Nokogiri::XML(res).css('result').first['code'] == '1000'
# handle_non_epp_errors(nil, Nokogiri::XML(res).css('result').text)
# end
def server
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
port = ENV['epp_port'] || 700
@server ||= Epp::Server.new({ server: ENV['epp_hostname'], tag: current_user.username,
password: current_user.plain_text_password,
port: port,
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key) })
end
def request_params
params.require(:xml_console).permit(:payload)
end
end

View file

@ -10,6 +10,8 @@ class EisBilling::EInvoiceResponseController < EisBilling::BaseController
def mark_e_invoice_sent_at(invoice_number)
invoice = Invoice.find_by(number: invoice_number)
invoice = Invoice.find_by(number: invoice_number['invoice_number']) if invoice.nil?
invoice.update(e_invoice_sent_at: Time.zone.now)
end
end

View file

@ -20,13 +20,23 @@ module Epp
rescue_from StandardError, with: :respond_with_command_failed_error
rescue_from AuthorizationError, with: :respond_with_authorization_error
rescue_from Shunter::ThrottleError, with: :respond_with_session_limit_exceeded_error
rescue_from ActiveRecord::RecordNotFound, with: :respond_with_object_does_not_exist_error
before_action :set_paper_trail_whodunnit
skip_before_action :validate_against_schema
protected
def respond_with_session_limit_exceeded_error(exception)
epp_errors.add(:epp_errors,
code: '2502',
msg: Shunter.default_error_message)
handle_errors
log_exception(exception) unless Rails.env.test?
end
def respond_with_command_failed_error(exception)
epp_errors.add(:epp_errors,
code: '2400',
@ -51,6 +61,11 @@ module Epp
private
def throttled_user
authorize!(:throttled_user, @domain) unless current_user || instance_of?(Epp::SessionsController)
current_user
end
def wrap_exceptions
yield
rescue CanCan::AccessDenied

View file

@ -5,6 +5,9 @@ module Epp
before_action :find_contact, only: [:info, :update, :delete]
before_action :find_password, only: [:info, :update, :delete]
THROTTLED_ACTIONS = %i[info check create renew update transfer delete].freeze
include Shunter::Integration::Throttle
def info
authorize! :info, @contact, @password
render_epp_response 'epp/contacts/info'

View file

@ -6,6 +6,9 @@ module Epp
before_action :set_paper_trail_whodunnit
before_action :parse_schemas_prefix_and_version
THROTTLED_ACTIONS = %i[info create check renew update transfer delete].freeze
include Shunter::Integration::Throttle
def info
authorize! :info, @domain

View file

@ -1,5 +1,8 @@
module Epp
class PollsController < BaseController
THROTTLED_ACTIONS = %i[poll].freeze
include Shunter::Integration::Throttle
def poll
authorize! :manage, :poll
req_poll if params[:parsed_frame].css('poll').first['op'] == 'req'

View file

@ -3,6 +3,9 @@ module Epp
skip_authorization_check only: [:hello, :login, :logout]
before_action :set_paper_trail_whodunnit
THROTTLED_ACTIONS = %i[login hello].freeze
include Shunter::Integration::Throttle
def hello
render_epp_response('greeting')
end

View file

@ -1,31 +0,0 @@
class Registrar
class AccountActivitiesController < BaseController
load_and_authorize_resource
def index
params[:q] ||= {}
account = current_registrar_user.registrar.cash_account
ca_cache = params[:q][:created_at_lteq]
begin
end_time = params[:q][:created_at_lteq].try(:to_date)
params[:q][:created_at_lteq] = end_time.try(:end_of_day)
rescue
logger.warn('Invalid date')
end
@q = account.activities.includes(:invoice).ransack(params[:q])
@q.sorts = 'id desc' if @q.sorts.empty?
respond_to do |format|
format.html { @account_activities = @q.result.page(params[:page]) }
format.csv do
raw_csv = CsvGenerator.generate_csv(@q.result)
send_data raw_csv, filename: "account_activities_#{Time.zone.now.to_formatted_s(:number)}.csv"
end
end
params[:q][:created_at_lteq] = ca_cache
end
end
end

View file

@ -1,34 +0,0 @@
class Registrar
class AccountController < BaseController
skip_authorization_check
helper_method :iban_max_length
helper_method :balance_auto_reload_setting
def show; end
def edit
@registrar = current_registrar_user.registrar
end
def update
@registrar = current_registrar_user.registrar
@registrar.update!(registrar_params)
redirect_to registrar_account_path, notice: t('.saved')
end
private
def registrar_params
params.require(:registrar).permit(:billing_email, :iban)
end
def iban_max_length
Iban.max_length
end
def balance_auto_reload_setting
current_registrar_user.registrar.settings['balance_auto_reload']
end
end
end

View file

@ -1,21 +0,0 @@
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)
action = Actions::DoRequest.new(request, uri)
response = action.call
start_notice = t('.replaced')
process_response(response: response,
start_notice: start_notice,
active_tab: ACTIVE_TAB)
end
end
end

View file

@ -1,43 +0,0 @@
class Registrar
class BaseController < ApplicationController
include Registrar::ApplicationHelper
before_action :authenticate_registrar_user!
before_action :check_ip_restriction
helper_method :depp_controller?
helper_method :head_title_sufix
before_action :set_paper_trail_whodunnit
protected
def current_ability
@current_ability ||= Ability.new(current_registrar_user, request.remote_ip)
end
private
def check_ip_restriction
ip_restriction = Authorization::RestrictedIp.new(request.ip)
allowed = ip_restriction.can_access_registrar_area?(current_registrar_user.registrar)
return if allowed
sign_out current_registrar_user
flash[:alert] = t('registrar.authorization.ip_not_allowed', ip: request.ip)
redirect_to new_registrar_user_session_url
end
def depp_controller?
false
end
def head_title_sufix
t(:registrar_head_title_sufix)
end
def user_for_paper_trail
current_registrar_user ? current_registrar_user.id_role_username : 'anonymous'
end
end
end

View file

@ -1,105 +0,0 @@
class Registrar
class BulkChangeController < DeppController
helper_method :available_contacts
def new
authorize! :manage, :repp
@expire_date = Time.zone.now.to_date
render 'registrar/bulk_change/new', locals: { active_tab: default_tab }
end
def bulk_renew
authorize! :manage, :repp
set_form_data
if ready_to_renew?
res = ReppApi.bulk_renew(domain_ids_for_bulk_renew, params[:period],
current_registrar_user)
flash_message(JSON.parse(res))
else
flash[:notice] = nil
end
render 'registrar/bulk_change/new', locals: { active_tab: :bulk_renew }
end
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 '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 ready_to_renew?
domain_ids_for_bulk_renew.present? && params[:renew].present?
end
def set_form_data
@expire_date = params[:expire_date].to_date
@domains = domains_by_date(@expire_date)
@period = params[:period]
end
def available_contacts
current_registrar_user.registrar.contacts.order(:name).pluck(:name, :code)
end
def default_tab
:technical_contact
end
def domains_scope
current_registrar_user.registrar.domains
end
def domains_by_date(date)
domains_scope.where('valid_to <= ?', date)
end
def domain_ids_for_bulk_renew
params['domain_ids']&.reject { |id| id.blank? }
end
def renew_task(domains)
Domains::BulkRenew::Start.run(domains: domains,
period_element: @period,
registrar: current_registrar_user.registrar)
end
def flash_message(res)
flash[:notice] = res['code'] == 1000 ? t(:bulk_renew_completed) : res['message']
end
end
end

View file

@ -1,163 +0,0 @@
class Registrar
class ContactsController < DeppController
before_action :init_epp_contact
helper_method :address_processing?
helper_method :ident_types
helper_method :domain_filter_params
def index
authorize! :view, Depp::Contact
params[:q] ||= {}
params[:q].delete_if { |_k, v| v.blank? }
search_params = params[:q].deep_dup
if search_params[:domain_contacts_type_in].is_a?(Array) &&
search_params[:domain_contacts_type_in].delete('registrant')
search_params[:registrant_domains_id_not_null] = 1
end
contacts = current_registrar_user.registrar.contacts.includes(:registrar)
status_list = params[:statuses_contains]
if status_list
contacts_ids = contacts.select { |c| (c.statuses & status_list.to_a) == status_list.to_a }
.map(&:id)
contacts = contacts.where(id: contacts_ids)
end
normalize_search_parameters do
@q = contacts.ransack(search_params)
end
contacts = @q.result
respond_to do |format|
format.html do
contacts_per_page = params[:results_per_page].to_i
@contacts = contacts.page(params[:page])
@contacts = @contacts.per(contacts_per_page) if contacts_per_page.positive?
end
format.csv do
raw_csv = CsvGenerator.generate_csv(contacts)
send_data raw_csv, filename: 'contacts.csv', type: "#{Mime[:csv]}; charset=utf-8"
end
format.pdf do
raw_html = ApplicationController.render(
template: 'registrar/contacts/list_pdf',
assigns: { contacts: contacts },
formats: [:html]
)
raw_pdf = contacts.pdf(raw_html)
send_data raw_pdf, filename: 'contacts.pdf'
end
end
end
def new
authorize! :create, Depp::Contact
@contact = Depp::Contact.new
end
def show
authorize! :view, Depp::Contact
@contact = Depp::Contact.find_by_id(params[:id])
end
def edit
authorize! :edit, Depp::Contact
@contact = Depp::Contact.find_by_id(params[:id])
end
def create
authorize! :create, Depp::Contact
@contact = Depp::Contact.new(contact_params)
if @contact.save
redirect_to registrar_contact_url(@contact.id)
else
render 'new'
end
end
def update
authorize! :edit, Depp::Contact
@contact = Depp::Contact.new(contact_params)
if @contact.update_attributes(contact_params)
redirect_to registrar_contact_url(@contact.id)
else
render 'edit'
end
end
def delete
authorize! :delete, Depp::Contact
@contact = Depp::Contact.find_by_id(params[:id])
end
def destroy
authorize! :delete, Depp::Contact
@contact = Depp::Contact.new(contact_params_for_delete)
if @contact.delete
redirect_to registrar_contacts_url, notice: t(:destroyed)
else
render 'delete'
end
end
protected
def domain_filter_params
params.permit(:domain_filter)
end
private
def init_epp_contact
Depp::Contact.user = depp_current_user
end
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 address_processing?
Contact.address_processing?
end
def ident_types
Contact::Ident.types
end
def contact_params
params.require(:depp_contact).permit(:id,
:name,
:email,
:phone,
:org_name,
:ident, :ident_type, :ident_country_code,
:street, :city, :zip, :state, :country_code,
:password,
:legal_document,
:code)
end
def contact_params_for_delete
params.require(:depp_contact).permit(:id, :password, :legal_document)
end
end
end

View file

@ -1,18 +0,0 @@
class Registrar
class CurrentUserController < BaseController
skip_authorization_check
def switch
raise 'Cannot switch to unlinked user' unless current_registrar_user.linked_with?(new_user)
sign_in(:registrar_user, new_user)
redirect_back(fallback_location: root_path, notice: t('.switched', new_user: new_user))
end
private
def new_user
@new_user ||= ApiUser.find(params[:new_user_id])
end
end
end

View file

@ -1,28 +0,0 @@
class Registrar
class DepositsController < BaseController
authorize_resource class: false
def new
@deposit = Deposit.new
end
def create
@deposit = Deposit.new(deposit_params.merge(registrar: current_registrar_user.registrar))
@invoice = @deposit.issue_prepayment_invoice
if @invoice
flash[:notice] = t(:please_pay_the_following_invoice)
redirect_to [:registrar, @invoice]
else
flash[:alert] = @deposit.errors.full_messages.join(', ')
redirect_to new_registrar_deposit_path
end
end
private
def deposit_params
params.require(:deposit).permit(:amount, :description)
end
end
end

View file

@ -1,37 +0,0 @@
class Registrar
class DeppController < BaseController
helper_method :depp_current_user
rescue_from(Errno::ECONNRESET, Errno::ECONNREFUSED) do |exception|
logger.error 'COULD NOT CONNECT TO REGISTRY'
logger.error exception.backtrace.join("\n")
redirect_to new_registrar_user_session_url, alert: t(:no_connection_to_registry)
end
before_action :authenticate_user
def authenticate_user
redirect_to new_registrar_user_session_url and return unless depp_current_user
end
def depp_controller?
true
end
def depp_current_user
return nil unless current_registrar_user
@depp_current_user ||= Depp::User.new(
tag: current_registrar_user.username,
password: current_registrar_user.plain_text_password
)
end
def response_ok?
@data.css('result').each do |x|
success_codes = %(1000, 1001, 1300, 1301)
return false unless success_codes.include?(x['code'])
end
true
end
end
end

View file

@ -1,49 +0,0 @@
class Registrar
class DomainTransfersController < BulkChangeController
before_action do
authorize! :transfer, Depp::Domain
end
def new
end
def create
if params[:batch_file].present?
csv = CSV.read(params[:batch_file].path, headers: true)
domain_transfers = []
csv.each do |row|
domain_name = row['Domain']
transfer_code = row['Transfer code']
domain_transfers << { 'domain_name' => domain_name, 'transfer_code' => transfer_code }
end
uri = URI.parse("#{ENV['repp_url']}domains/transfer")
request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
request.body = { data: { domain_transfers: domain_transfers } }.to_json
request.basic_auth(current_registrar_user.username,
current_registrar_user.plain_text_password)
action = Actions::DoRequest.new(request, uri)
response = action.call
parsed_response = JSON.parse(response.body, symbolize_names: true)
if response.code == '200'
failed = parsed_response[:data][:failed].pluck(:domain_name).join(', ')
flash[:notice] = t('.transferred', count: parsed_response[:data][:success].size,
failed: failed)
redirect_to registrar_domains_url
else
@api_errors = parsed_response[:message]
render 'registrar/bulk_change/new', locals: { active_tab: :bulk_transfer }
end
else
params[:request] = true # EPP domain:transfer "op" attribute
domain = Depp::Domain.new(current_user: depp_current_user)
@data = domain.transfer(params)
render :new unless response_ok?
end
end
end
end

View file

@ -1,227 +0,0 @@
class Registrar
class DomainsController < DeppController
before_action :init_domain, except: :new
helper_method :contacts
helper_method :search_params
def index
authorize! :view, Depp::Domain
if search_params.to_h.delete_if { |_key, value| value.blank? }.length == 1 &&
search_params[:name_matches].present?
domain = Domain.find_by(name: search_params[:name_matches])
redirect_to info_registrar_domains_url(domain_name: domain.name) and return if domain
end
domains = if params[:statuses_contains]
current_domain_scope.where('domains.statuses @> ?::varchar[]',
"{#{params[:statuses_contains].join(',')}}")
else
current_domain_scope
end
domains = domains.where(contacts: { ident: params[:contacts_ident_eq] }) if params[:contacts_ident_eq]
normalize_search_parameters do
@q = domains.ransack(search_params.except(:contacts_ident_eq))
@domains = @q.result.page(params[:page])
# if we do not get any results, add wildcards to the name field and search again
if @domains.count == 0 && search_params[:name_matches] !~ /^%.+%$/
new_search_params = search_params.to_h.except(:contacts_ident_eq)
new_search_params[:name_matches] = "%#{new_search_params[:name_matches]}%"
@q = domains.ransack(new_search_params)
@domains = @q.result.page(params[:page])
end
end
respond_to do |format|
format.html
format.csv do
domain_presenters = []
@q.result.find_each do |domain|
domain_presenters << ::DomainPresenter.new(domain: domain, view: view_context)
end
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"
end
end
end
def current_domain_scope
current_registrar_user.registrar.domains.includes(:registrar, :registrant)
end
def info
authorize! :info, Depp::Domain
@data = @domain.info(params[:domain_name]) if params[:domain_name]
@pending_delete = domain_delete_pending(@data)
@client_holded = client_holded(@data)
if response_ok?
render 'info'
else
flash[:alert] = @data.css('msg').text
redirect_to registrar_domains_url and return
end
end
def check
authorize! :check, Depp::Domain
if params[:domain_name]
@data = @domain.check(params[:domain_name])
render 'check_index' and return unless response_ok?
else
render 'check_index'
end
end
def new
authorize! :create, Depp::Domain
@domain_params = Depp::Domain.default_params
@domain_params[:period] = Depp::Domain.default_period
end
# rubocop:disable Metrics/CognitiveComplexity
def create
authorize! :create, Depp::Domain
@domain_params = domain_params.to_h
@data = @domain.create(@domain_params)
if @data && response_ok?
redirect_to info_registrar_domains_url(domain_name: @domain_params[:name])
else
flash[:alert] = t('.email_error_message') unless @emails_check_result
render 'new'
end
end
def edit
authorize! :update, Depp::Domain
@data = @domain.info(params[:domain_name])
@domain_params = Depp::Domain.construct_params_from_server_data(@data)
@dispute = Dispute.active.find_by(domain_name: params[:domain_name])
end
def update
authorize! :update, Depp::Domain
@domain_params = params[:domain]
@data = @domain.update(@domain_params)
@dispute = Dispute.active.find_by(domain_name: @domain_params[:name])
if @data && response_ok?
redirect_to info_registrar_domains_url(domain_name: @domain_params[:name])
else
flash[:alert] = t('.email_error_message') unless @emails_check_result
params[:domain_name] = @domain_params[:name]
render 'new'
end
end
# rubocop:enable Metrics/CognitiveComplexity
def delete
authorize! :delete, Depp::Domain
end
def destroy
authorize! :delete, Depp::Domain
@data = @domain.delete(params[:domain])
@results = @data.css('result')
if response_ok?
flash[:notice] = t('.deleting_request')
redirect_to info_registrar_domains_url(domain_name: params[:domain][:name])
else
params[:domain_name] = params[:domain][:name]
render 'delete'
end
end
def renew
authorize! :renew, Depp::Domain
if params[:domain_name] && params[:cur_exp_date]
@data = @domain.renew(params)
render 'renew_index' and return unless response_ok?
else
params[:period] = Depp::Domain.default_period
render 'renew_index'
end
end
def search_contacts
authorize! :create, Depp::Domain
scope = current_registrar_user.registrar.contacts.limit(10)
if params[:query].present?
escaped_str = ActiveRecord::Base.connection.quote_string params[:query]
scope = scope.where("name ilike '%#{escaped_str}%' OR code ilike '%#{escaped_str}%' ")
end
render json: scope.pluck(:name, :code).map { |c| { display_key: "#{c.second} #{c.first}", value: c.second } }
end
def remove_hold
authorize! :remove_hold, Depp::Domain
return unless params[:domain_name]
@data = @domain.remove_hold(params)
flash[:alert] = @data.css('msg').text unless response_ok?
redirect_to info_registrar_domains_url(domain_name: params[:domain_name])
end
private
def init_domain
@domain = Depp::Domain.new(current_user: depp_current_user)
end
def client_holded(data)
data.css('status')&.map { |element| element.attribute('s').value }
&.any? { |status| status == DomainStatus::CLIENT_HOLD }
end
def domain_delete_pending(data)
data.css('status')&.map { |element| element.attribute('s').value }
&.any? { |status| status.include?(DomainStatus::PENDING_DELETE) }
end
def contacts
current_registrar_user.registrar.contacts
end
def normalize_search_parameters
ca_cache = search_params[:valid_to_lteq]
begin
end_time = search_params[:valid_to_lteq].try(:to_date)
search_params[:valid_to_lteq] = end_time.try(:end_of_day)
rescue
logger.warn('Invalid date')
end
yield
search_params[:valid_to_lteq] = ca_cache
end
def search_params
params.fetch(:q, {}).permit(:name_matches,
:registrant_ident_eq,
:contacts_ident_eq,
:nameservers_hostname_eq,
:valid_to_gteq,
:valid_to_lteq,
:s)
end
def domain_params
params.require(:domain).permit(:name, :period, :registrant, :registrant_helper, :reserved_pw,
:verified, :legal_document, contacts_attributes: {},
nameservers_attributes: {},
dnskeys_attributes: {})
end
end
end

View file

@ -1,13 +0,0 @@
class Registrar
module Invoices
class DeliveryController < BaseController
include Deliverable
private
def redirect_url
registrar_invoice_path(@invoice)
end
end
end
end

View file

@ -1,38 +0,0 @@
class Registrar
class InvoicesController < BaseController
load_and_authorize_resource
def index
params[:q] ||= {}
invoices = current_registrar_user.registrar.invoices.includes(:items, :account_activity)
normalize_search_parameters do
@q = invoices.ransack(params[:q])
@q.sorts = 'id desc' if @q.sorts.empty?
@invoices = @q.result.page(params[:page])
end
end
def show; end
def cancel
@invoice.cancel
EisBilling::SendInvoiceStatus.send_info(invoice_number: @invoice.number, status: 'cancelled')
redirect_to [:registrar, @invoice], notice: t('.cancelled')
end
def download
filename = "invoice-#{@invoice.number}.pdf"
send_data @invoice.as_pdf, filename: filename
end
private
def normalize_search_parameters
params[:q][:total_gteq].gsub!(',', '.') if params[:q][:total_gteq]
params[:q][:total_lteq].gsub!(',', '.') if params[:q][:total_lteq]
yield
end
end
end

View file

@ -1,65 +0,0 @@
class Registrar
class NameserversController < BulkChangeController
def update
authorize! :manage, :repp
ipv4 = params[:ipv4].split("\r\n")
ipv6 = params[:ipv6].split("\r\n")
uri = URI.parse("#{ENV['repp_url']}registrar/nameservers")
domains = domain_list_from_csv
return csv_list_empty_guard if domains == []
options = {
uri: uri,
ipv4: ipv4,
ipv6: ipv6,
}
action = Actions::BulkNameserversChange.new(params, domains, current_registrar_user, options)
response = action.call
parsed_response = JSON.parse(response.body, symbolize_names: true)
if response.code == '200'
redirect_to(registrar_domains_url,
flash: { notice: compose_notice_message(parsed_response) })
else
@api_errors = parsed_response[:message]
render 'registrar/bulk_change/new', locals: { active_tab: :nameserver }
end
end
def compose_notice_message(res)
action_text = params[:old_hostname].blank? ? t('.added') : t('.replaced')
notices = ["#{action_text}. #{t('.affected_domains')}: " \
"#{res[:data][:affected_domains].join(', ')}"]
notices << "#{t('.skipped_domains')}: #{res[:data][:skipped_domains].join(', ')}" if res[:data][:skipped_domains]
notices.join(', ')
end
def csv_list_empty_guard
notice = 'CSV scoped domain list seems empty. Make sure that domains are added and ' \
'"Domain" header is present.'
redirect_to(registrar_domains_url, flash: { notice: notice })
end
def domain_list_from_csv
return if params[:puny_file].blank?
domains = []
csv = CSV.read(params[:puny_file].path, headers: true)
return [] if csv['Domain'].blank?
csv.map { |b| domains << b['Domain'] }
domains.compact
rescue CSV::MalformedCSVError
[]
end
end
end

View file

@ -1,66 +0,0 @@
class Registrar
class PaymentsController < BaseController
protect_from_forgery except: [:back, :callback]
skip_authorization_check # actually anyone can pay, no problems at all
skip_before_action :authenticate_registrar_user!, :check_ip_restriction,
only: [:back, :callback]
before_action :check_supported_payment_method, only: [:pay]
def pay
invoice = Invoice.find(params[:invoice_id])
channel = params[:bank]
@payment_order = PaymentOrder.new_with_type(type: channel, invoice: invoice)
@payment_order.save
@payment_order.reload
@payment_order.return_url = registrar_return_payment_with_url(@payment_order)
@payment_order.response_url = registrar_response_payment_with_url(@payment_order)
@payment_order.save
@payment_order.reload
end
def back
@payment_order = PaymentOrder.find_by!(id: params[:payment_order])
@payment_order.update!(response: params.to_unsafe_h)
if @payment_order.payment_received?
@payment_order.complete_transaction
if @payment_order.invoice.paid?
flash[:notice] = t('.payment_successful')
else
flash[:alert] = t('.successful_payment_backend_error')
end
else
@payment_order.create_failure_report
flash[:alert] = t('.payment_not_received')
end
redirect_to registrar_invoice_path(@payment_order.invoice)
end
def callback
@payment_order = PaymentOrder.find_by!(id: params[:payment_order])
@payment_order.update!(response: params.to_unsafe_h)
if @payment_order.payment_received?
@payment_order.complete_transaction
else
@payment_order.create_failure_report
end
render status: 200, json: { status: 'ok' }
end
private
def check_supported_payment_method
return if PaymentOrder.supported_method?(params[:bank], shortname: true)
raise(StandardError, 'Not supported payment method')
end
end
end

View file

@ -1,44 +0,0 @@
class Registrar
class PollsController < DeppController
authorize_resource class: false
before_action :init_epp_xml
def show
if Rails.env.test? # Stub for depp server request
@data = Object.new
def @data.css(key)
; [];
end
else
@data = depp_current_user.request(@ex.poll)
end
end
def destroy
@data = depp_current_user.request(@ex.poll(poll: { value: '', attrs: { op: 'ack', msgID: params[:id] } }))
@results = @data.css('result')
@data = depp_current_user.request(@ex.poll)
render 'show'
end
def confirm_transfer
domain_params = params[:domain]
@data = @domain.confirm_transfer(domain_params)
@results = @data.css('result')
@data = depp_current_user.request(@ex.poll)
render 'show'
end
private
def init_epp_xml
@ex = EppXml::Session.new(cl_trid_prefix: depp_current_user.tag)
@domain = Depp::Domain.new(current_user: depp_current_user)
end
end
end

View file

@ -1,108 +0,0 @@
class Registrar
class SessionsController < Devise::SessionsController
before_action :check_ip_restriction
helper_method :depp_controller?
def create
@depp_user = Depp::User.new(depp_user_params)
if @depp_user.pki && request.env['HTTP_SSL_CLIENT_S_DN_CN'].blank?
@depp_user.errors.add(:base, :webserver_missing_user_name_directive)
end
if @depp_user.pki && request.env['HTTP_SSL_CLIENT_CERT'].blank?
@depp_user.errors.add(:base, :webserver_missing_client_cert_directive)
end
if @depp_user.pki && request.env['HTTP_SSL_CLIENT_S_DN_CN'] == '(null)'
@depp_user.errors.add(:base, :webserver_user_name_directive_should_be_required)
end
if @depp_user.pki && request.env['HTTP_SSL_CLIENT_CERT'] == '(null)'
@depp_user.errors.add(:base, :webserver_client_cert_directive_should_be_required)
end
@api_user = ApiUser.find_by(username: sign_in_params[:username],
plain_text_password: sign_in_params[:password])
unless @api_user
@depp_user.errors.add(:base, t(:no_such_user))
show_error and return
end
if @depp_user.pki && !@api_user.pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'],
request.env['HTTP_SSL_CLIENT_S_DN_CN'], api: false)
@depp_user.errors.add(:base, :invalid_cert)
end
show_error and return unless @depp_user.errors.none?
if @api_user.active?
sign_in_and_redirect(:registrar_user, @api_user)
else
@depp_user.errors.add(:base, :not_active)
show_error
end
end
private
def depp_controller?
false
end
def find_user_by_idc(idc)
return User.new unless idc
ApiUser.find_by(identity_code: idc) || User.new
end
def find_user_by_idc_and_allowed(idc)
return User.new unless idc
possible_users = ApiUser.where(identity_code: idc) || User.new
possible_users.each do |selected_user|
return selected_user if selected_user.registrar.white_ips.registrar_area.include_ip?(request.ip)
end
end
def check_ip_restriction
ip_restriction = Authorization::RestrictedIp.new(request.ip)
allowed = ip_restriction.can_access_registrar_area_sign_in_page?
return if allowed
render plain: t('registrar.authorization.ip_not_allowed', ip: request.ip)
end
def current_ability
@current_ability ||= Ability.new(current_registrar_user, request.remote_ip)
end
def after_sign_in_path_for(_resource_or_scope)
if can?(:show, :poll)
registrar_root_path
else
registrar_account_path
end
end
def after_sign_out_path_for(_resource_or_scope)
new_registrar_user_session_path
end
def user_for_paper_trail
current_registrar_user ? current_registrar_user.id_role_username : 'anonymous'
end
def depp_user_params
params = sign_in_params
params[:tag] = params.delete(:username)
params.merge!(pki: !(Rails.env.development? || Rails.env.test?))
params
end
def show_error
redirect_to new_registrar_user_session_url, alert: @depp_user.errors.full_messages.first
end
end
end

View file

@ -1,52 +0,0 @@
class Registrar
module Settings
class BalanceAutoReloadController < BaseController
before_action :authorize
def edit
@type = if current_registrar.settings['balance_auto_reload']
type_params = current_registrar.settings['balance_auto_reload']['type']
.except('name')
BalanceAutoReloadTypes::Threshold.new(type_params)
else
BalanceAutoReloadTypes::Threshold.new
end
end
def update
type = BalanceAutoReloadTypes::Threshold.new(type_params)
current_registrar.update!(settings: { balance_auto_reload: { type: type } })
redirect_to registrar_account_path, notice: t('.saved')
end
def destroy
current_registrar.settings.delete('balance_auto_reload')
current_registrar.save!
redirect_to registrar_account_path, notice: t('.disabled')
end
private
def type_params
permitted_params = params.require(:type).permit(:amount, :threshold)
normalize_params(permitted_params)
end
def normalize_params(params)
params[:amount] = params[:amount].to_f
params[:threshold] = params[:threshold].to_f
params
end
def authorize
authorize!(:manage, :balance_auto_reload)
end
def current_registrar
current_registrar_user.registrar
end
end
end
end

View file

@ -1,22 +0,0 @@
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 = BASE_URL
request = form_request(uri)
action = Actions::DoRequest.new(request, uri)
response = action.call
start_notice = t('.replaced')
process_response(response: response,
start_notice: start_notice,
active_tab: ACTIVE_TAB)
end
end
end

View file

@ -1,62 +0,0 @@
class Registrar
class XmlConsolesController < DeppController
PREFS = %w[
domain-ee
contact-ee
eis
epp-ee
].freeze
authorize_resource class: false
def show; end
def create
begin
@result = depp_current_user.server.request(params[:payload])
rescue StandardError
@result = 'CONNECTION ERROR - Is the EPP server running?'
end
render :show
end
def load_xml
cl_trid = "#{depp_current_user.tag}-#{Time.zone.now.to_i}"
xml_dir_path = Rails.root.join('app/views/registrar/xml_consoles/epp_requests').to_s
xml = File.read("#{xml_dir_path}/#{params[:obj]}/#{params[:epp_action]}.xml")
xml = prepare_payload(xml, cl_trid)
render plain: xml
end
private
def prepare_payload(xml, cl_trid)
PREFS.map do |pref|
xml = load_schema_by_prefix(pref, xml)
end
xml.gsub!('<clTRID>ABC-12345</clTRID>', "<clTRID>#{cl_trid}</clTRID>")
xml
end
def load_schema_by_prefix(pref, xml)
case pref
when 'epp-ee'
insert_prefix_and_version(xml, pref, '1.0')
when 'eis'
insert_prefix_and_version(xml, pref, '1.0')
when 'contact-ee'
insert_prefix_and_version(xml, pref, '1.1')
else
insert_prefix_and_version(xml, pref, '1.2')
end
end
def insert_prefix_and_version(xml, pref, version)
xml.gsub!("\"#{pref}\"",
"\"#{Xsd::Schema.filename(for_prefix: pref.to_s, for_version: version)}\"")
xml
end
end
end

View file

@ -3,6 +3,11 @@ module Repp
class AccountsController < BaseController # rubocop:disable Metrics/ClassLength
load_and_authorize_resource
THROTTLED_ACTIONS = %i[
index balance details update_auto_reload_balance disable_auto_reload_balance switch_user update
].freeze
include Shunter::Integration::Throttle
api :get, '/repp/v1/accounts'
desc 'Get all activities'
def index

View file

@ -27,6 +27,10 @@ module Repp
@response = { code: 2201, message: 'Authorization error' }
logger.error e.to_s
render(json: @response, status: :unauthorized)
rescue Shunter::ThrottleError => e
@response = { code: 2502, message: Shunter.default_error_message }
logger.error e.to_s unless Rails.env.test?
render(json: @response, status: :bad_request)
ensure
create_repp_log
end
@ -167,6 +171,11 @@ module Repp
data[:abilities] = Ability.new(current_user).permissions
data
end
def throttled_user
authorize!(:throttled_user, @domain) unless current_user || action_name == 'tara_callback'
current_user
end
end
end
end

View file

@ -5,6 +5,9 @@ module Repp
before_action :find_contact, only: %i[show update destroy]
skip_around_action :log_request, only: :search
THROTTLED_ACTIONS = %i[index check search create show update destroy].freeze
include Shunter::Integration::Throttle
api :get, '/repp/v1/contacts'
desc 'Get all existing contacts'
def index

View file

@ -2,6 +2,9 @@ module Repp
module V1
module Domains
class AdminContactsController < BaseContactsController
THROTTLED_ACTIONS = %i[update].freeze
include Shunter::Integration::Throttle
def update
super

View file

@ -4,6 +4,9 @@ module Repp
class ContactsController < BaseContactsController
before_action :set_domain, only: %i[index create destroy]
THROTTLED_ACTIONS = %i[index create destroy update].freeze
include Shunter::Integration::Throttle
def_param_group :contacts_apidoc do
param :contacts, Array, required: true, desc: 'Array of new linked contacts' do
param :code, String, required: true, desc: 'Contact code'
@ -38,9 +41,7 @@ module Repp
def cta(action = 'add')
params[:contacts].each { |c| c[:action] = action }
action = Actions::DomainUpdate.new(@domain, contact_create_params, false)
# rubocop:disable Style/AndOr
handle_errors(@domain) and return unless action.call
# rubocop:enable Style/AndOr
render_success(data: { domain: { name: @domain.name } })
end

View file

@ -4,6 +4,9 @@ module Repp
class DnssecController < BaseController
before_action :set_domain, only: %i[index create destroy]
THROTTLED_ACTIONS = %i[index create destroy].freeze
include Shunter::Integration::Throttle
def_param_group :dns_keys_apidoc do
param :flags, String, required: true, desc: '256 (KSK) or 257 (ZSK)'
param :protocol, String, required: true, desc: 'Key protocol (3)'

View file

@ -5,6 +5,9 @@ module Repp
before_action :set_domain, only: %i[index create destroy]
before_action :set_nameserver, only: %i[destroy]
THROTTLED_ACTIONS = %i[index create destroy].freeze
include Shunter::Integration::Throttle
api :GET, '/repp/v1/domains/:domain_name/nameservers'
desc "Get domain's nameservers"
def index

View file

@ -6,6 +6,9 @@ module Repp
before_action :select_renewable_domains, only: [:bulk_renew]
before_action :set_domain, only: [:create]
THROTTLED_ACTIONS = %i[create bulk_renew].freeze
include Shunter::Integration::Throttle
api :POST, 'repp/v1/domains/:domain_name/renew'
desc 'Renew domain'
param :renews, Hash, required: true, desc: 'Renew parameters' do
@ -43,7 +46,7 @@ module Repp
def validate_renew_period
@epp_errors ||= ActiveModel::Errors.new(self)
periods = Depp::Domain::PERIODS.map { |p| p[1] }
periods = Domain::PERIODS.map { |p| p[1] }
return if periods.include? bulk_renew_params[:renew_period]
@epp_errors.add(:epp_errors, msg: 'Invalid renew period', code: '2005')

View file

@ -5,6 +5,9 @@ module Repp
before_action :set_domain, only: %i[update destroy]
before_action :verify_status
THROTTLED_ACTIONS = %i[update destroy].freeze
include Shunter::Integration::Throttle
api :DELETE, '/repp/v1/domains/:domain_name/statuses/:status'
param :domain_name, String, desc: 'Domain name'
desc 'Remove status from specific domain'

View file

@ -4,6 +4,9 @@ module Repp
class TransfersController < BaseController
before_action :set_domain, only: [:create]
THROTTLED_ACTIONS = %i[create].freeze
include Shunter::Integration::Throttle
api :POST, 'repp/v1/domains/:domain_name/transfer'
desc 'Transfer a specific domain'
param :transfer, Hash, required: true, desc: 'Renew parameters' do

View file

@ -8,6 +8,9 @@ module Repp
before_action :forward_registrar_id, only: %i[create update destroy]
before_action :set_domain, only: %i[update]
THROTTLED_ACTIONS = %i[transfer_info transfer index create show update destroy].freeze
include Shunter::Integration::Throttle
api :GET, '/repp/v1/domains'
desc 'Get all existing domains'
def index

View file

@ -4,6 +4,9 @@ module Repp
class InvoicesController < BaseController # rubocop:disable Metrics/ClassLength
load_and_authorize_resource
THROTTLED_ACTIONS = %i[download add_credit send_to_recipient cancel index show].freeze
include Shunter::Integration::Throttle
# rubocop:disable Metrics/MethodLength
api :get, '/repp/v1/invoices'
desc 'Get all invoices'

View file

@ -3,8 +3,11 @@ module Repp
module Registrar
class AccreditationInfoController < BaseController
if Feature.allow_accr_endspoints?
api :GET, 'repp/v1/registrar/accreditation/get_info'
desc 'check login user and return data'
THROTTLED_ACTIONS = %i[index].freeze
include Shunter::Integration::Throttle
api :GET, 'repp/v1/registrar/accreditation/get_info'
desc 'check login user and return data'
def index
login = current_user

View file

@ -6,6 +6,9 @@ module Repp
skip_before_action :check_ip_restriction, only: :tara_callback
skip_before_action :validate_client_certs, only: :tara_callback
THROTTLED_ACTIONS = %i[index tara_callback].freeze
include Shunter::Integration::Throttle
api :GET, 'repp/v1/registrar/auth'
desc 'check user auth info and return data'
def index

View file

@ -4,6 +4,9 @@ module Repp
class NameserversController < BaseController
before_action :verify_nameserver_existance, only: %i[update]
THROTTLED_ACTIONS = %i[put].freeze
include Shunter::Integration::Throttle
api :PUT, 'repp/v1/registrar/nameservers'
desc 'bulk nameserver change'
param :data, Hash, required: true, desc: 'Object holding nameserver changes' do

View file

@ -4,6 +4,9 @@ module Repp
class NotificationsController < BaseController
before_action :set_notification, only: %i[update show]
THROTTLED_ACTIONS = %i[all_notifications index show update].freeze
include Shunter::Integration::Throttle
api :GET, '/repp/v1/registrar/notifications'
desc 'Get the latest unread poll message'
def index

View file

@ -2,6 +2,9 @@ module Repp
module V1
module Registrar
class SummaryController < BaseController
THROTTLED_ACTIONS = %i[index].freeze
include Shunter::Integration::Throttle
api :GET, 'repp/v1/registrar/summary'
desc 'check user summary info and return data'

View file

@ -0,0 +1,55 @@
module Repp
module V1
module Registrar
class XmlConsoleController < BaseController
include EppRequestable
THROTTLED_ACTIONS = %i[load_xml].freeze
include Shunter::Integration::Throttle
PREFS = %w[domain-ee contact-ee eis epp-ee].freeze
SCHEMA_VERSIONS = {
'epp-ee' => '1.0',
'eis' => '1.0',
'contact-ee' => '1.1',
'default' => '1.2',
}.freeze
def load_xml
cl_trid = "#{current_user.username}-#{Time.zone.now.to_i}"
obj = ActionController::Base.helpers.sanitize(params[:obj])
epp_action = ActionController::Base.helpers.sanitize(params[:epp_action])
xml_dir_path = Rails.root.join('app/views/epp/sample_requests').to_s
xml = File.read("#{xml_dir_path}/#{obj}/#{epp_action}.xml")
xml = prepare_payload(xml, cl_trid)
render_success(data: { xml: xml })
end
private
def prepare_payload(xml, cl_trid)
PREFS.map do |pref|
xml = load_schema_by_prefix(pref, xml)
end
xml.gsub!('<clTRID>ABC-12345</clTRID>', "<clTRID>#{cl_trid}</clTRID>")
xml
end
def load_schema_by_prefix(pref, xml)
version = version_by_prefix(pref)
xml.gsub!("\"#{pref}\"",
"\"#{Xsd::Schema.filename(for_prefix: pref.to_s, for_version: version)}\"")
xml
end
def version_by_prefix(pref)
key = SCHEMA_VERSIONS.key?(pref) ? pref : 'default'
SCHEMA_VERSIONS[key]
end
end
end
end
end

View file

@ -90,6 +90,8 @@ module Repp
def calculate_market_share(domains_by_rar)
sum = domains_by_rar.values.sum
return domains_by_rar if sum.zero?
domains_by_rar.transform_values do |v|
value = v.to_f / sum * 100.0
value < 0.1 ? value.round(3) : value.round(1)

View file

@ -1,6 +0,0 @@
module Registrar::ApplicationHelper
def env_style
return '' if unstable_env.nil?
"background-image: url(#{image_path("registrar/bg-#{unstable_env}.png")});"
end
end

View file

@ -30,7 +30,7 @@ module Actions
end
def check_for_same_contacts(contacts, contact_type)
return unless contacts.uniq.count != contacts.count
return if contacts.uniq.count == contacts.count
domain.add_epp_error('2306', contact_type, nil, %i[domain_contacts invalid])
end
@ -194,22 +194,33 @@ module Actions
def contact_for_action(action:, method:, code:)
contact = Epp::Contact.find_by(code: code)
return contact if action == 'add' || !contact
return domain.admin_domain_contacts.find_by(contact_id: contact.id) if method == 'admin'
domain.tech_domain_contacts.find_by(contact_id: contact.id)
existing_contact(id: contact.id, admin: method == 'admin')
end
def assign_contact(obj, add: false, admin: true, code:)
def existing_contact(id:, admin: true)
return domain.admin_domain_contacts.find_by(contact_id: id) if admin
domain.tech_domain_contacts.find_by(contact_id: id)
end
def assign_contact(obj, code:, add: false, admin: true)
if obj.blank?
domain.add_epp_error('2303', 'contact', code, %i[domain_contacts not_found])
elsif obj.try(:org?) && admin && add
domain.add_epp_error('2306', 'contact', code,
%i[domain_contacts admin_contact_can_be_only_private_person])
else
add ? { contact_id: obj.id, contact_code: obj.code } : { id: obj.id, _destroy: 1 }
assigned_contact_hash(obj, add, admin)
end
end
def assigned_contact_hash(obj, add, admin)
return if !existing_contact(id: obj.id, admin: admin).nil? && add
add ? { contact_id: obj.id, contact_code: obj.code } : { id: obj.id, _destroy: 1 }
end
def assign_requested_statuses
return unless params[:statuses]

View file

@ -11,7 +11,6 @@ module Actions
def call
result = check_email(email)
save_result(result)
filtering_old_failed_records(result)
result.success ? log_success : log_failure(result)
result.success
end
@ -26,27 +25,25 @@ module Actions
Rails.env.test? && check_level == 'smtp' ? :mx : check_level.to_sym
end
def filtering_old_failed_records(result)
if @check_level == "mx" && !result.success && validation_eventable.validation_events.count > 3
validation_eventable.validation_events.order!(created_at: :asc)
while validation_eventable.validation_events.count > 3
validation_eventable.validation_events.first.destroy
end
def filtering_old_failed_records(result, contact)
ValidationEvent::INVALID_EVENTS_COUNT_BY_LEVEL.each do |level, limit|
handle_failed_records(contact: contact, check_level: level, limit: limit, success: result.success)
end
end
if @check_level == "mx" && result.success && validation_eventable.validation_events.count > 1
validation_eventable.validation_events.order!(created_at: :asc)
while validation_eventable.validation_events.count > 1
validation_eventable.validation_events.first.destroy
def handle_failed_records(contact:, check_level:, limit:, success:)
if @check_level.to_sym == check_level && !success && contact.validation_events.count > limit
contact.validation_events.order!(created_at: :asc)
while contact.validation_events.count > limit
contact.validation_events.first.destroy
end
end
end
if @check_level == "smtp" && validation_eventable.validation_events.count > 1
validation_eventable.validation_events.order!(created_at: :asc)
while validation_eventable.validation_events.count > 1
validation_eventable.validation_events.first.destroy
end
end
def filtering_old_records(contact:, success:)
return unless success
contact.validation_events.destroy_all
end
def save_result(result)
@ -61,9 +58,14 @@ module Actions
result.success = result_validation.present?
end
result.configuration = nil
contacts.find_in_batches(batch_size: 500) do |contact_batches|
contact_batches.each do |contact|
# methods should be in this order!
filtering_old_records(contact: contact, success: result.success)
contact.validation_events.create(validation_event_attrs(result))
filtering_old_failed_records(result, contact)
end
end
rescue ActiveRecord::RecordNotSaved

View file

@ -6,8 +6,8 @@ class CheckForceDeleteLift < ApplicationJob
.select { |d| d.registrant.need_to_lift_force_delete? }
handle_refresh_status(domains) if domains.present?
domains = Domain.where("force_delete_data->'template_name' = ?", 'invalid_email')
.where("force_delete_data->'force_delete_type' = ?", 'soft')
domains = (domains + Domain.where("force_delete_data->'template_name' = ?", 'invalid_email')
.where("force_delete_data->'force_delete_type' = ?", 'soft')).uniq
domains.each do |domain|
Domains::ForceDeleteLift::Base.run(domain: domain)
@ -39,15 +39,5 @@ class CheckForceDeleteLift < ApplicationJob
domain.status_notes[DomainStatus::FORCE_DELETE].slice!(registrant.email_history)
domain.status_notes[DomainStatus::FORCE_DELETE].lstrip!
domain.save(validate: false)
notify_registrar(domain) unless domain.status_notes[DomainStatus::FORCE_DELETE].empty?
end
def notify_registrar(domain)
domain.registrar.notifications.create!(text: I18n.t('force_delete_auto_email',
domain_name: domain.name,
outzone_date: domain.outzone_date,
purge_date: domain.purge_date,
email: domain.status_notes[DomainStatus::FORCE_DELETE]))
end
end

View file

@ -0,0 +1,21 @@
class OutzoneInvalidEmailDomainsJob < ApplicationJob
queue_as :default
def perform
domains = Domain.where("force_delete_data->'template_name' = ?", 'invalid_email')
.where(outzone_at: nil)
.where('Date(force_delete_start) <= ?', Time.zone.now)
domains.each do |domain|
outzone(domain)
end
end
private
def outzone(domain)
domain.outzone_at = domain.force_delete_start + Domain.expire_warning_period
domain.delete_date = domain.outzone_at + Domain.redemption_grace_period
domain.save
end
end

View file

@ -2,8 +2,9 @@ class SendMonthlyInvoicesJob < ApplicationJob
queue_as :default
discard_on StandardError
def perform(dry: false, months_ago: 1)
def perform(dry: false, months_ago: 1, overwrite: false)
@dry = dry
@overwrite = overwrite
@month = Time.zone.now - months_ago.month
@directo_data = []
@ -48,7 +49,7 @@ class SendMonthlyInvoicesJob < ApplicationJob
def find_or_init_monthly_invoices(invoices: [])
Registrar.with_cash_accounts.find_each do |registrar|
invoice = registrar.find_or_init_monthly_invoice(month: @month)
invoice = registrar.find_or_init_monthly_invoice(month: @month, overwrite: @overwrite)
invoices << invoice unless invoice.nil?
end
invoices

36
app/lib/shunter.rb Normal file
View file

@ -0,0 +1,36 @@
# frozen_string_literal: true
module Shunter
module_function
class ThrottleError < StandardError; end
BASE_LOGGER = ::Logger.new($stdout)
ONE_MINUTE = 60
ONE_HUNDRED_REQUESTS = 100
BASE_CONNECTION = {
host: ENV['shunter_redis_host'] || 'redis',
port: (ENV['shunter_redis_port'] || '6379').to_i,
}.freeze
def default_error_message
"Session limit exceeded. Current limit is #{default_threshold} in #{default_timespan} seconds"
end
def default_timespan
ENV['shunter_default_timespan'] || ONE_MINUTE
end
def default_threshold
ENV['shunter_default_threshold'] || ONE_HUNDRED_REQUESTS
end
def default_adapter
ENV['shunter_default_adapter'] || 'Shunter::Adapters::Redis'
end
def feature_enabled?
ActiveModel::Type::Boolean.new.cast(ENV['shunter_enabled'] || 'false')
end
end

View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
module Shunter
module Adapters
class Memory
attr_reader :store
def initialize(_options = {})
@@store ||= {}
end
def find_counter(key)
@@store[key]
end
def write_counter(key)
@@store[key] = 1
end
def increment_counter(key)
@@store[key] += 1
end
def clear!
@@store = {}
end
def expire_counter(_key, _timespan); end
end
end
end

View file

@ -0,0 +1,29 @@
# frozen_string_literal: true
module Shunter
module Adapters
class Redis
attr_reader :redis
def initialize(options)
@redis = ::Redis.new(options)
end
def find_counter(key)
@redis.get(key)
end
def write_counter(key)
@redis.set(key, 1)
end
def increment_counter(key)
@redis.incr(key)
end
def expire_counter(key, timespan)
@redis.expire(key, timespan)
end
end
end
end

63
app/lib/shunter/base.rb Normal file
View file

@ -0,0 +1,63 @@
# frozen_string_literal: true
module Shunter
class Base
attr_accessor :user_id, :adapter
def initialize(options = {})
@user_id = options[:user_id]
adapter_klass = Shunter.default_adapter.constantize
@adapter = adapter_klass.new(options[:conn_options])
end
def user_key
"counting_#{@user_id}"
end
def blocked_user_key
"blocked_#{@user_id}"
end
def throttle
return false if blocked?
valid_counter?
end
def blocked?
adapter.find_counter(blocked_user_key).present?
end
def valid_counter?
if adapter.find_counter(user_key)
number_of_requests = adapter.increment_counter(user_key)
if number_of_requests > allowed_requests.to_i
init_counter(blocked_user_key)
return false
end
else
init_counter(user_key)
end
true
end
private
def init_counter(key)
adapter.write_counter(key)
adapter.expire_counter(key, timespan)
end
def allowed_requests
Shunter.default_threshold
end
def timespan
Shunter.default_timespan
end
def logger
Shunter::BASE_LOGGER
end
end
end

View file

@ -0,0 +1,44 @@
# frozen_string_literal: true
require 'active_support/concern'
module Shunter
module Integration
module Throttle
extend ActiveSupport::Concern
included do |base|
actions = base.const_defined?('THROTTLED_ACTIONS') && base.const_get('THROTTLED_ACTIONS')
return if actions.blank?
around_action :throttle, only: actions
def throttle
if throttled_user.blank? || !Shunter.feature_enabled?
yield if block_given?
return
end
user_id = throttled_user.id
shunter = Shunter::Base.new(conn_options: connection_options, user_id: user_id)
if shunter.throttle
logger.info "Request from #{throttled_user.class}/#{throttled_user.id} is coming through throttling"
yield if block_given?
else
logger.info "Too many requests from #{throttled_user.class}/#{throttled_user.id}." unless Rails.env.test?
raise Shunter::ThrottleError
end
end
end
def connection_options
Shunter::BASE_CONNECTION
end
def logger
Shunter::BASE_LOGGER
end
end
end
end

View file

@ -31,12 +31,6 @@ class Ability
end
def epp # Registrar/api_user dynamic role
if @user.registrar.api_ip_white?(@ip)
can :manage, Depp::Contact
can :manage, :xml_console
can :manage, Depp::Domain
end
can :manage, Account
# Poll
@ -122,7 +116,6 @@ class Ability
customer_service
can :manage, :registrant_domains
can :manage, :registrant_whois
can :manage, Depp::Domain
can :manage, Domain
end

View file

@ -37,6 +37,24 @@ class Auction < ApplicationRecord
find_by(domain: domain_name.to_s, status: PENDING_STATUSES)
end
def self.domain_exists_in_blocked_disputed_and_registered?(domain_name)
Domain.exists?(name: domain_name) ||
BlockedDomain.exists?(name: domain_name) ||
Dispute.exists?(domain_name: domain_name) ||
exception_for_registred_or_unbided_existed_auctions(domain_name)
end
def self.exception_for_registred_or_unbided_existed_auctions(domain_name)
return false unless Auction.exists?(domain: domain_name)
auctions = Auction.where(domain: domain_name).order(:created_at)
last_record = auctions.last
return false if last_record.domain_registered? || last_record.no_bids?
true
end
def start
self.status = self.class.statuses[:started]
save!

View file

@ -59,8 +59,9 @@ module Invoice::BookKeeping
duration.times do |dur|
single_item_dup = single_item.dup
single_item_dup['start_date'] = (issue_date + dur.year).end_of_month.strftime('%Y-%m-%d')
single_item_dup['end_date'] = (issue_date + (dur + 1).year).end_of_month.strftime('%Y-%m-%d')
date = (issue_date + dur.year).end_of_month.strftime('%Y-%m-%d')
single_item_dup['start_date'] = date
single_item_dup['end_date'] = date
single_item_dup['price'] = (item['price'].to_f / duration).round(2)
lines << single_item_dup
end

View file

@ -38,15 +38,26 @@ module Registrar::BookKeeping
lines.as_json
end
def find_or_init_monthly_invoice(month:)
def find_or_init_monthly_invoice(month:, overwrite:)
invoice = invoices.find_by(monthly_invoice: true, issue_date: month.end_of_month.to_date,
cancelled_at: nil)
return invoice if invoice
return invoice if invoice && !overwrite
summary = monthly_summary(month: month)
return unless summary
init_monthly_invoice(summary)
new_invoice = init_monthly_invoice(summary)
return overwrite_invoice(invoice, new_invoice) if invoice && overwrite
new_invoice
end
def overwrite_invoice(original_invoice, new_invoice)
params_to_scrub = %i[created_at updated_at id number sent_at
e_invoice_sent_at in_directo cancelled_at payment_link]
attrs = new_invoice.attributes.with_indifferent_access.except(*params_to_scrub)
original_invoice.update(attrs)
original_invoice
end
def title_for_summary(date)

View file

@ -32,27 +32,40 @@ module Zone::WhoisQueryable
# Take note - since this concern only used to zone whois queries, dnssec keys are set to
# empty array
def domain_vars
{ disclaimer: Setting.registry_whois_disclaimer, name: origin,
{
disclaimer: Setting.registry_whois_disclaimer, name: origin,
registered: created_at.try(:to_s, :iso8601), status: ['ok (paid and in zone)'],
changed: updated_at.try(:to_s, :iso8601), email: Setting.registry_email,
admin_contacts: [contact_vars], tech_contacts: [contact_vars],
nameservers: nameserver_vars, dnssec_keys: [], dnssec_changed: nil }
nameservers: nameserver_vars, dnssec_keys: [],
dnssec_changed: nil
}
end
def registrar_vars
{ registrar: Setting.registry_juridical_name, registrar_website: Setting.registry_url,
registrar_phone: Setting.registry_phone }
{
registrar: Setting.registry_juridical_name,
registrar_website: Setting.registry_url,
registrar_phone: Setting.registry_phone,
}
end
def registrant_vars
{ registrant: Setting.registry_juridical_name, registrant_reg_no: Setting.registry_reg_no,
registrant_ident_country_code: Setting.registry_country_code, registrant_kind: 'org',
registrant_disclosed_attributes: %w[name email] }
{
registrant: Setting.registry_juridical_name,
registrant_reg_no: Setting.registry_reg_no,
registrant_ident_country_code: Setting.registry_country_code,
registrant_kind: 'org',
registrant_disclosed_attributes: %w[name email phone],
}
end
def contact_vars
{ name: Setting.registry_invoice_contact, email: Setting.registry_email,
disclosed_attributes: %w[name email] }
{
name: Setting.registry_invoice_contact,
email: Setting.registry_email,
disclosed_attributes: %w[name email],
}
end
def nameserver_vars

View file

@ -64,6 +64,8 @@ class Contact < ApplicationRecord
validate :validate_html
validate :validate_country_code, if: -> { self.class.address_processing? }
validates :registrant_publishable, inclusion: { in: [true, false] }, if: -> { registrant? }
# validates :registrant_publishable, inclusion: { in: [false] }, unless: -> { registrant? }
after_initialize do
self.status_notes = {} if status_notes.nil?
@ -145,6 +147,19 @@ class Contact < ApplicationRecord
# "clientDeleteProhibited" or "serverDeleteProhibited" status.
PENDING_DELETE = 'pendingDelete'.freeze
DISCLOSE_ATTRIBUTES = %w[
name
email
phone
registrant_publishable
address
fax
].freeze
OPEN_LEGAL_ATTRIBUTES = %w[
phone
].freeze
STATUSES = [
CLIENT_DELETE_PROHIBITED, SERVER_DELETE_PROHIBITED,
CLIENT_TRANSFER_PROHIBITED,

View file

@ -15,15 +15,6 @@ class ContactRequest < ApplicationRecord
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']
@ -31,11 +22,22 @@ class ContactRequest < ApplicationRecord
save!
end
def self.create_random_secret
SecureRandom.hex(64)
end
class << self
def 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 self.set_valid_to_24_hours_from_now
(Time.zone.now + 24.hours)
def create_random_secret
SecureRandom.hex(64)
end
def set_valid_to_24_hours_from_now
(Time.zone.now + 24.hours)
end
end
end

View file

@ -1,318 +0,0 @@
module Depp
class Contact
include ActiveModel::Model
attr_accessor :id, :name, :email, :phone, :org_name,
:ident, :ident_type, :ident_country_code,
:street, :city, :zip, :state, :country_code,
:password, :legal_document, :statuses, :code,
:email_history
DISABLED = 'Disabled'
DISCLOSURE_TYPES = [DISABLED, '1', '0']
TYPES = %w( org priv birthday )
SELECTION_TYPES = [
['Business code', 'org'],
['Personal identification code', 'priv'],
['Birthday', 'birthday']
]
validates :phone, e164: true, phone: true
class << self
attr_reader :epp_xml, :user
def new_from_params(params)
new(
id: params[:code],
code: params[:code],
email: params[:email],
phone: params[:phone],
ident: params[:ident],
ident_type: params[:ident_type],
ident_country_code: params[:ident_country_code],
# postalInfo
name: params[:name],
org_name: params[:org_name],
# address
street: params[:street],
city: params[:city],
zip: params[:zip],
state: params[:state],
country_code: params[:country_code]
)
end
def find_by_id(id)
data = info_xml(id)
res = data.css('epp response resData infData')
ext = data.css('epp response extension')
new(
id: res.css('id').text,
code: res.css('id').text,
email: res.css('email').text,
phone: res.css('voice').text,
ident: ext.css('ident').text,
ident_type: ext.css('ident').first.try(:attributes).try(:[], 'type').try(:value),
ident_country_code: ext.css('ident').first.try(:attributes).try(:[], 'cc').try(:value),
# postalInfo
name: res.css('postalInfo name').text,
org_name: res.css('postalInfo org').text,
# address
street: res.css('postalInfo addr street').text,
city: res.css('postalInfo addr city').text,
zip: res.css('postalInfo addr pc').text,
state: res.css('postalInfo addr sp').text,
country_code: res.css('postalInfo addr cc').text,
# authInfo
password: res.css('authInfo pw').text,
# statuses
statuses: data.css('status').map { |s| [s['s'], s.text] }
)
end
def user=(user)
@user = user
@epp_xml = EppXml::Contact.new(cl_trid_prefix: user.tag, schema_prefix: 'contact-ee',
schema_version: '1.1')
end
def info_xml(id, password = nil)
xml = epp_xml.info(
id: { value: id },
authInfo: { pw: { value: password } }
)
user.request(xml)
end
def construct_check_hash_from_data(data)
res = data.css('epp response resData chkData cd')
@contacts = []
res.each do |_r|
id = res.css('id').try(:text)
reason = res.css('reason').present? ? res.css('reason').text : I18n.t(:available)
@contacts << { id: id, reason: reason }
end
@contacts
end
def contact_id_from_xml(data)
id = data.css('epp response resData creData id').text
id.blank? ? nil : id
end
def construct_create_disclosure_xml(cph, flag)
xml = { disclose: {} }
cph.each do |k, v|
xml[:disclose][k] = {}
xml[:disclose][k][:value] = v
end
xml[:disclose][:attrs] = {}
xml[:disclose][:attrs][:flag] = flag
xml.with_indifferent_access
end
# cpd = contact_params[:disclose]
def extract_disclosure_hash(cpd)
return {} unless cpd
cpd.delete_if { |k, v| v if v != '1' && k == 'flag' }
end
def extract_info_disclosure(data)
hash = {}
data.css('disclose').each do |d|
flag = d.attributes['flag'].value
next unless flag
hash[flag] = {}
d.children.each do |c|
hash[flag][c.name] = flag if %w( name email fax voice addr org_name ).include?(c.name)
end
end
hash
end
def type_string(type_code)
return '' if type_code.blank?
t = SELECTION_TYPES.select { |tp| tp.second == type_code }
t.try(:first).try(:first)
end
end
def save
return false unless valid?
hash = {
id: { value: code },
postalInfo: {
name: { value: name },
org: { value: org_name },
},
voice: { value: phone },
email: { value: email }
}
if ::Contact.address_processing?
hash[:postalInfo][:addr] = {
street: { value: street },
city: { value: city },
sp: { value: state },
pc: { value: zip },
cc: { value: country_code },
}
end
hash[:id] = nil if code.blank?
create_xml = Depp::Contact.epp_xml.create(hash, extension_xml(:create))
data = Depp::Contact.user.request(create_xml)
self.id = data.css('id').text
handle_errors(data)
end
# rubocop:disable Metrics/MethodLength
def update_attributes(params)
return false unless valid?
self.ident_country_code = params[:ident_country_code]
self.ident_type = params[:ident_type]
self.ident = params[:ident]
self.name = params[:name]
self.email = params[:email]
self.phone = params[:phone]
self.org_name = params[:org_name]
if ::Contact.address_processing?
self.street = params[:street]
self.city = params[:city]
self.zip = params[:zip]
self.state = params[:state]
self.country_code = params[:country_code]
end
attributes = {
id: { value: id },
chg: {
postalInfo: {
name: { value: name },
org: { value: org_name },
},
voice: { value: phone },
email: { value: email },
authInfo: {
pw: { value: password }
}
}
}
if ::Contact.address_processing?
attributes[:chg][:postalInfo][:addr] = {
street: { value: street },
city: { value: city },
sp: { value: state },
pc: { value: zip },
cc: { value: country_code }
}
end
update_xml = Depp::Contact.epp_xml.update(attributes, extension_xml(:update))
data = Depp::Contact.user.request(update_xml)
handle_errors(data)
end
# rubocop:enable Metrics/MethodLength
def delete
delete_xml = Contact.epp_xml.delete(
{
id: { value: id },
authInfo: { pw: { value: password } }
},
extension_xml(:delete)
)
data = Depp::Contact.user.request(delete_xml)
handle_errors(data)
end
def extension_xml(action)
xml = { _anonymus: [] }
case action
when :create
ident = ident_xml[:_anonymus].try(:first)
when :update
# detect if any ident has changed, nb! ident and self.ident is not always same
unless ident == self.ident && ident == ident_type && ident_country_code == self.ident_country_code
ident = ident_xml[:_anonymus].try(:first)
end
end
legal = legal_document_xml[:_anonymus].try(:first)
xml[:_anonymus] << ident if ident.present?
xml[:_anonymus] << legal if legal.present?
xml
end
def ident_xml
{
_anonymus: [
ident: { value: ident, attrs: { type: ident_type, cc: ident_country_code } }
]
}
end
def legal_document_xml
return {} if legal_document.blank?
type = legal_document.original_filename.split('.').last.downcase
{
_anonymus: [
legalDocument: { value: Base64.encode64(legal_document.read), attrs: { type: type } }
]
}
end
def check(id)
xml = epp_xml.check(id: { value: id })
current_user.request(xml)
end
def country_name
Country.new(country_code) || 'No access'
end
def org?
ident_type == 'org'
end
def priv?
ident_type == 'priv'
end
def persisted?
id.present?
end
def handle_errors(data)
data.css('result').each do |x|
success_codes = %(1000, 1300, 1301)
next if success_codes.include?(x['code'])
message = "#{x.css('msg').text} #{x.css('value').text}"
attr = message.split('[').last.strip.sub(']', '') if message.include?('[')
attr = :base if attr.nil?
attr = 'phone' if attr == 'voice'
attr = 'zip' if attr == 'pc'
errors.add(attr, message)
end
errors.blank?
end
end
end

View file

@ -1,26 +0,0 @@
module Depp
class Dnskey
FLAGS = [
['0 - not for DNSSEC validation', 0],
['256 - ZSK', 256],
['257 - KSK', 257]
]
ALGORITHMS = [
['3 - DSA/SHA-1', 3],
['5 - RSA/SHA-1', 5],
['6 - DSA-NSEC3-SHA1', 6],
['7 - RSASHA1-NSEC3-SHA1', 7],
['8 - RSA/SHA-256', 8],
['10 - RSA/SHA-512', 10],
['13 - ECDSA Curve P-256 with SHA-256', 13],
['14 - ECDSA Curve P-384 with SHA-384', 14],
['15 - Ed25519', 15],
['16 - Ed448', 16],
].freeze
PROTOCOLS = [3]
DS_DIGEST_TYPES = [1, 2]
end
end

View file

@ -1,351 +0,0 @@
module Depp
class Domain
include ActiveModel::Conversion
include RemoveHold
extend ActiveModel::Naming
attr_accessor :name, :current_user, :epp_xml
STATUSES = %w[
clientDeleteProhibited
clientHold
clientRenewProhibited
clientTransferProhibited
clientUpdateProhibited
].freeze
PERIODS = [
['3 months', '3m'],
['6 months', '6m'],
['9 months', '9m'],
['1 year', '1y'],
['2 years', '2y'],
['3 years', '3y'],
['4 years', '4y'],
['5 years', '5y'],
['6 years', '6y'],
['7 years', '7y'],
['8 years', '8y'],
['9 years', '9y'],
['10 years', '10y'],
].freeze
def initialize(args = {})
self.current_user = args[:current_user]
self.epp_xml = EppXml::Domain.new(
cl_trid_prefix: current_user.tag,
schema_prefix: 'domain-ee',
schema_version: '1.1'
)
end
def info(domain_name)
xml = epp_xml.info(name: { value: domain_name })
current_user.request(xml)
end
def check(domain_name)
xml = epp_xml.check(
_anonymus: [
name: { value: domain_name }
]
)
current_user.request(xml)
end
def create(domain_params)
dns_hash = {}
keys = Domain.create_dnskeys_hash(domain_params)
dns_hash[:_anonymus] = keys if keys.any?
period = domain_params[:period].to_i.to_s
period_unit = domain_params[:period][-1].to_s
xml = if domain_params[:nameservers_attributes]
.select { |_key, value| value['hostname'].present? }.any?
epp_xml.create({
name: { value: domain_params[:name] },
period: { value: period, attrs: { unit: period_unit } },
ns: Domain.create_nameservers_hash(domain_params),
registrant: { value: domain_params[:registrant] },
_anonymus: Domain.create_contacts_hash(domain_params)
}, dns_hash, Domain.construct_custom_params_hash(domain_params))
else
epp_xml.create({
name: { value: domain_params[:name] },
period: { value: period, attrs: { unit: period_unit } },
registrant: { value: domain_params[:registrant] },
_anonymus: Domain.create_contacts_hash(domain_params)
}, dns_hash, Domain.construct_custom_params_hash(domain_params))
end
current_user.request(xml)
end
def update(domain_params)
data = current_user.request(epp_xml.info(name: { value: domain_params[:name] }))
old_domain_params = Depp::Domain.construct_params_from_server_data(data)
xml = epp_xml.update(
Depp::Domain.construct_edit_hash(domain_params, old_domain_params),
Depp::Domain.construct_ext_edit_hash(domain_params, old_domain_params),
Depp::Domain.construct_custom_params_hash(domain_params)
)
current_user.request(xml)
end
def delete(domain_params)
xml = epp_xml.delete({
name: { value: domain_params[:name] },
},
Depp::Domain.construct_custom_params_hash(domain_params),
(domain_params[:verified].present? && 'yes'))
current_user.request(xml)
end
def renew(params)
period = params[:period].to_i.to_s
period_unit = params[:period][-1].to_s
current_user.request(epp_xml.renew(name: { value: params[:domain_name] },
curExpDate: { value: params[:cur_exp_date] },
period: { value: period, attrs: { unit: period_unit } }))
end
def transfer(params)
op = params[:request] ? 'request' : nil
op = params[:query] ? 'query' : op
op = params[:approve] ? 'approve' : op
op = params[:reject] ? 'reject' : op
current_user.request(epp_xml.transfer({
name: { value: params[:domain_name] },
authInfo: { pw: { value: params[:transfer_code] } }
}, op, Domain.construct_custom_params_hash(params)))
end
def confirm_transfer(domain_params)
data = current_user.request(epp_xml.info(name: { value: domain_params[:name] }))
pw = data.css('pw').text
xml = epp_xml.transfer({
name: { value: domain_params[:name] },
authInfo: { pw: { value: pw } }
}, 'approve')
current_user.request(xml)
end
class << self
def default_period
'1y'
end
def default_params
ret = {}
ret[:contacts_attributes] ||= {}
ENV['default_admin_contacts_count'].to_i.times do |i|
ret[:contacts_attributes][i] = { code: '', type: 'admin' }
end
ret[:nameservers_attributes] ||= {}
ENV['default_nameservers_count'].to_i.times do |i|
ret[:nameservers_attributes][i] = {}
end
ret[:dnskeys_attributes] ||= { 0 => {} }
ret[:statuses_attributes] ||= { 0 => {} }
ret.with_indifferent_access
end
def construct_params_from_server_data(data)
ret = default_params
ret[:name] = data.css('name').text
ret[:registrant] = data.css('registrant').text
data.css('contact').each_with_index do |x, i|
ret[:contacts_attributes][i] = { code: x.text, type: x['type'] }
end
data.css('hostAttr').each_with_index do |x, i|
ret[:nameservers_attributes][i] = {
hostname: x.css('hostName').text,
ipv4: Array(x.css('hostAddr[ip="v4"]')).map(&:text).join(','),
ipv6: Array(x.css('hostAddr[ip="v6"]')).map(&:text).join(',')
}
end
data.css('keyData').each_with_index do |x, i|
ret[:dnskeys_attributes][i] = {
flags: x.css('flags').text,
protocol: x.css('protocol').text,
alg: x.css('alg').text,
public_key: x.css('pubKey').text,
ds_key_tag: x.css('keyTag').first.try(:text),
ds_alg: x.css('alg').first.try(:text),
ds_digest_type: x.css('digestType').first.try(:text),
ds_digest: x.css('digest').first.try(:text)
}
end
data.css('status').each_with_index do |x, i|
next unless STATUSES.include?(x['s'])
ret[:statuses_attributes][i] = {
code: x['s'],
description: x.text
}
end
ret
end
def construct_custom_params_hash(domain_params)
custom_params = { _anonymus: [] }
if domain_params[:legal_document].present?
type = domain_params[:legal_document].original_filename.split('.').last.downcase
custom_params[:_anonymus] << {
legalDocument: { value: Base64.encode64(domain_params[:legal_document].read), attrs: { type: type } }
}
end
if domain_params[:reserved_pw].present?
custom_params[:_anonymus] << { reserved: { pw: { value: domain_params[:reserved_pw] } } }
end
custom_params
end
def construct_edit_hash(domain_params, old_domain_params)
contacts = array_difference(create_contacts_hash(domain_params), create_contacts_hash(old_domain_params))
add_anon = contacts
contacts = array_difference(create_contacts_hash(old_domain_params), create_contacts_hash(domain_params))
rem_anon = contacts
add_arr = []
add_ns = create_nameservers_hash(domain_params) - create_nameservers_hash(old_domain_params)
add_arr << { ns: add_ns } if add_ns.any?
add_arr << { _anonymus: add_anon } if add_anon.any?
rem_arr = []
rem_ns = create_nameservers_hash(old_domain_params) - create_nameservers_hash(domain_params)
rem_arr << { ns: rem_ns } if rem_ns.any?
rem_arr << { _anonymus: rem_anon } if rem_anon.any?
if domain_params[:registrant] != old_domain_params[:registrant]
chg = [{ registrant: { value: domain_params[:registrant] } }] unless domain_params[:verified].present?
if domain_params[:verified]
chg = [{ registrant: { value: domain_params[:registrant], attrs: { verified: 'yes' } } }]
end
end
add_arr = nil if add_arr.none?
rem_arr = nil if rem_arr.none?
{
name: { value: domain_params[:name] },
add: add_arr,
rem: rem_arr,
chg: chg
}
end
def construct_ext_edit_hash(domain_params, old_domain_params)
rem_keys = create_dnskeys_hash(old_domain_params) - create_dnskeys_hash(domain_params)
add_keys = create_dnskeys_hash(domain_params) - create_dnskeys_hash(old_domain_params)
hash = {}
hash[:rem] = rem_keys if rem_keys.any?
hash[:add] = add_keys if add_keys.any?
hash
end
def create_nameservers_hash(domain_params)
ret = []
domain_params[:nameservers_attributes].each do |_k, v|
next if v['hostname'].blank?
host_attr = []
host_attr << { hostName: { value: v['hostname'] } }
if v['ipv4'].present?
v['ipv4'].to_s.split(',').each do |ip|
host_attr << { hostAddr: { value: ip, attrs: { ip: 'v4' } } }
end
end
if v['ipv6'].present?
v['ipv6'].to_s.split(',').each do |ip|
host_attr << { hostAddr: { value: ip, attrs: { ip: 'v6' } } }
end
end
ret << { hostAttr: host_attr }
end
ret
end
def create_contacts_hash(domain_params)
ret = []
domain_params[:contacts_attributes].each do |_k, v|
next if v['code'].blank?
ret << {
contact: { value: v['code'], attrs: { type: v['type'] } }
}
end
ret
end
def create_dnskeys_hash(domain_params)
ret = []
domain_params[:dnskeys_attributes].each do |_k, v|
if v['ds_key_tag'].blank?
kd = create_key_data_hash(v)
if kd
ret << {
keyData: kd
}
end
else
ret << {
dsData: [
keyTag: { value: v['ds_key_tag'] },
alg: { value: v['ds_alg'] },
digestType: { value: v['ds_digest_type'] },
digest: { value: v['ds_digest'] },
keyData: create_key_data_hash(v)
]
}
end
end
ret
end
def create_key_data_hash(key_data_params)
return nil if key_data_params['public_key'].blank?
{
flags: { value: key_data_params['flags'] },
protocol: { value: key_data_params['protocol'] },
alg: { value: key_data_params['alg'] },
pubKey: { value: key_data_params['public_key'] }
}
end
def array_difference(x, y)
ret = x.dup
y.each do |element|
index = ret.index(element)
ret.delete_at(index) if index
end
ret
end
end
end
end

View file

@ -1,66 +0,0 @@
module Depp
class User
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :tag, :password, :pki
validates :tag, :password, presence: true
validate :validate_existance_in_server
def initialize(args = {})
args.each { |k, v| send("#{k}=", v) }
end
def server
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
port = ENV['epp_port'] || '700'
@server_cache ||= Epp::Server.new({
server: ENV['epp_hostname'],
tag: tag,
password: password,
port: port,
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)
})
end
def request(xml)
Nokogiri::XML(server.request(xml)).remove_namespaces!
rescue EppErrorResponse => e
Nokogiri::XML(e.response_xml.to_s).remove_namespaces!
end
private
def validate_existance_in_server
return if errors.any?
res = server.open_connection
unless Nokogiri::XML(res).css('greeting')
errors.add(:base, :failed_to_open_connection_to_epp_server)
server.close_connection # just in case
return
end
ex = EppXml::Session.new(cl_trid_prefix: tag)
xml = ex.login(clID: { value: tag }, pw: { value: password })
res = server.send_request(xml)
if Nokogiri::XML(res).css('result').first['code'] != '1000'
errors.add(:base, Nokogiri::XML(res).css('result').text)
end
server.close_connection
rescue OpenSSL::SSL::SSLError => e
Rails.logger.error "INVALID CERT: #{e}"
Rails.logger.error "INVALID CERT DEBUG INFO: epp_hostname: #{ENV['epp_hostname']}," \
"port: #{ENV['epp_port']}, cert_path: #{ENV['cert_path']}, key_path: #{ENV['key_path']}"
errors.add(:base, :invalid_cert)
end
end
end

View file

@ -25,10 +25,10 @@ class Dnskey < ApplicationRecord
}
# IANA numbers, single authority list
ALGORITHMS = Depp::Dnskey::ALGORITHMS.map {|pair| pair[1].to_s}.freeze
PROTOCOLS = %w(3)
FLAGS = %w(0 256 257) # 256 = ZSK, 257 = KSK
DS_DIGEST_TYPE = [1,2]
ALGORITHMS = %w[3 5 6 7 8 10 13 14 15 16].freeze
PROTOCOLS = %w[3].freeze
FLAGS = %w[0 256 257].freeze # 256 = ZSK, 257 = KSK
DS_DIGEST_TYPE = [1, 2].freeze
RESOLVERS = ENV['dnssec_resolver_ips'].to_s.strip.split(', ').freeze
self.ignored_columns = %w[legacy_domain_id]

View file

@ -13,6 +13,22 @@ class Domain < ApplicationRecord
include Domain::Disputable
include Domain::BulkUpdatable
PERIODS = [
['3 months', '3m'],
['6 months', '6m'],
['9 months', '9m'],
['1 year', '1y'],
['2 years', '2y'],
['3 years', '3y'],
['4 years', '4y'],
['5 years', '5y'],
['6 years', '6y'],
['7 years', '7y'],
['8 years', '8y'],
['9 years', '9y'],
['10 years', '10y'],
].freeze
attr_accessor :roles,
:legal_document_id,
:is_admin,
@ -49,7 +65,6 @@ class Domain < ApplicationRecord
statuses.include? DomainStatus::SERVER_REGISTRANT_CHANGE_PROHIBITED
end
# NB! contacts, admin_contacts, tech_contacts are empty for a new record
has_many :domain_contacts, dependent: :destroy
has_many :contacts, through: :domain_contacts, source: :contact

View file

@ -105,6 +105,9 @@ class Epp::Domain < Domain
max: Setting.ns_max_count
}
],
'2502' => [ # Rate limit exceeded
%i[base session_limit_exceeded],
],
]
}
end

View file

@ -62,7 +62,7 @@ module Epp
2308 => 'Data management policy violation',
2400 => 'Command failed',
2501 => 'Authentication error; server closing connection',
2502 => 'Session limit exceeded; server closing connection',
2502 => Shunter.default_error_message,
}.freeze
private_constant :DEFAULT_DESCRIPTIONS

View file

@ -1,4 +1,4 @@
class LegalDocument < ApplicationRecord
class LegalDocument < ApplicationRecord # rubocop:disable Metrics/ClassLength
include EppErrors
MIN_BODY_SIZE = (1.37 * 3.kilobytes).ceil
MAX_BODY_SIZE = 8.megabytes
@ -14,7 +14,7 @@ class LegalDocument < ApplicationRecord
belongs_to :documentable, polymorphic: true
validate :val_body_length, if: ->(file) { file.path.blank? }
validate :val_body_length, if: ->(file) { file.path.blank? && (Rails.env.production? || Rails.env.test?) }
before_create :add_creator
before_save :save_to_filesystem, if: :body
@ -24,7 +24,7 @@ class LegalDocument < ApplicationRecord
'2308' => [
%i[body length_more_than],
%i[body length_less_than],
]
],
}
end
@ -41,12 +41,13 @@ class LegalDocument < ApplicationRecord
digest = Digest::SHA1.new.update(binary).to_s
loop do
rand = SecureRandom.random_number.to_s.last(4)
next if rand.to_i == 0 || rand.length < 4
dir = "#{ENV['legal_documents_dir']}/#{Time.zone.now.strftime('%Y/%m/%d')}"
FileUtils.mkdir_p(dir, mode: 0775)
self.path = "#{dir}/#{Time.zone.now.to_formatted_s(:number)}_#{rand}.#{document_type}"
break unless File.file?(path)
rand = SecureRandom.random_number.to_s.last(4)
next if rand.to_i.zero? || rand.length < 4
dir = "#{ENV['legal_documents_dir']}/#{Time.zone.now.strftime('%Y/%m/%d')}"
FileUtils.mkdir_p(dir, mode: 0775)
self.path = "#{dir}/#{Time.zone.now.to_formatted_s(:number)}_#{rand}.#{document_type}"
break unless File.file?(path)
end
File.open(path, 'wb') { |f| f.write(binary) } unless Rails.env.test?
@ -69,50 +70,57 @@ class LegalDocument < ApplicationRecord
start = Time.zone.now.to_f
Rails.logger.info '-----> Removing legal documents duplicates'
count = 0
modified = Array.new
modified = []
LegalDocument.where(documentable_type: "Domain").where.not(checksum: [nil, ""]).find_each do |orig_legal|
LegalDocument.where(documentable_type: 'Domain')
.where.not(checksum: [nil, ''])
.find_each do |orig_legal|
next if modified.include?(orig_legal.checksum)
next if !File.exist?(orig_legal.path)
next unless File.exist?(orig_legal.path)
modified.push(orig_legal.checksum)
LegalDocument.where(documentable_type: "Domain", documentable_id: orig_legal.documentable_id).
where(checksum: orig_legal.checksum).
where.not(id: orig_legal.id).where.not(path: orig_legal.path).each do |new_legal|
unless modified.include?(orig_legal.id)
File.delete(new_legal.path) if File.exist?(new_legal.path)
new_legal.update(path: orig_legal.path)
count += 1
Rails.logger.info "File #{new_legal.path} has been removed by Domain "\
"#{new_legal.documentable_id}. Document id: #{new_legal.id}"
end
LegalDocument.where(documentable_type: 'Domain', documentable_id: orig_legal.documentable_id)
.where(checksum: orig_legal.checksum)
.where.not(id: orig_legal.id)
.where.not(path: orig_legal.path).each do |new_legal|
next if modified.include?(orig_legal.id)
File.delete(new_legal.path) if File.exist?(new_legal.path)
new_legal.update(path: orig_legal.path)
count += 1
Rails.logger.info "File #{new_legal.path} has been removed by Domain "\
"#{new_legal.documentable_id}. Document id: #{new_legal.id}"
end
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|
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 do |id|
case id
when Hash
id["id"]
when String
JSON.parse(id) rescue id.to_i
else
id
end
}.flatten.compact.uniq
LegalDocument.where(documentable_type: "Contact", documentable_id: contact_ids).
where(checksum: orig_legal.checksum).where.not(path: orig_legal.path).each do |new_legal|
unless modified.include?(orig_legal.id)
File.delete(new_legal.path) if File.exist?(new_legal.path)
new_legal.update(path: orig_legal.path)
count += 1
Rails.logger.info "File #{new_legal.path} has been removed by Contact "\
"#{new_legal.documentable_id}. Document id: #{new_legal.id}"
when Hash
id['id']
when String
JSON.parse(id) rescue id.to_i
else
id
end
end.flatten.compact.uniq
LegalDocument.where(documentable_type: 'Contact', documentable_id: contact_ids)
.where(checksum: orig_legal.checksum)
.where.not(path: orig_legal.path).each do |new_legal|
next if modified.include?(orig_legal.id)
File.delete(new_legal.path) if File.exist?(new_legal.path)
new_legal.update(path: orig_legal.path)
count += 1
Rails.logger.info "File #{new_legal.path} has been removed by Contact "\
"#{new_legal.documentable_id}. Document id: #{new_legal.id}"
end
end
Rails.logger.info "-----> Duplicates fixed for #{count} rows in #{(Time.zone.now.to_f - start).round(2)} seconds"
end
end

View file

@ -3,4 +3,8 @@ class Registrant < Contact
def epp_code_map
{}
end
def publishable?
registrant_publishable
end
end

View file

@ -23,7 +23,7 @@ class ValidationEvent < ApplicationRecord
smtp: 1,
}.freeze
store_accessor :event_data, :errors, :check_level, :email
store_accessor :event_data, :check_level, :email
belongs_to :validation_eventable, polymorphic: true

View file

@ -51,7 +51,9 @@ class WhoisRecord < ApplicationRecord
end
h[:email] = registrant.email
h[:registrant_changed] = registrant.updated_at.try(:to_s, :iso8601)
h[:phone] = registrant.phone
h[:registrant_publishable] = registrant.publishable?
h[:registrant_changed] = registrant.updated_at.try(:to_s, :iso8601)
h[:registrant_disclosed_attributes] = registrant.disclosed_attributes
h[:admin_contacts] = []
@ -78,7 +80,6 @@ class WhoisRecord < ApplicationRecord
h[:dnssec_keys] = domain.dnskeys.map { |key| "#{key.flags} #{key.protocol} #{key.alg} #{key.public_key}" }
h[:dnssec_changed] = domain.dnskeys.pluck(:updated_at).max.try(:to_s, :iso8601) rescue nil
h
end
@ -112,8 +113,10 @@ class WhoisRecord < ApplicationRecord
{
name: contact.name,
email: contact.email,
phone: contact.phone,
changed: contact.updated_at.try(:to_s, :iso8601),
disclosed_attributes: contact.disclosed_attributes,
contact_publishable: contact.registrant_publishable?,
}
end
end

View file

@ -1,45 +0,0 @@
class Registrar::DomainListCsvPresenter
def initialize(domains:, view:)
@domains = domains
@view = view
end
def to_s
table = CSV::Table.new([header])
domains.each do |domain|
table << domain_to_row(domain: domain)
end
table.to_s
end
private
def header
columns = %w[
domain_name
transfer_code
registrant_name
registrant_code
expire_time
]
columns.map! { |column| view.t("registrar.domains.index.csv.#{column}") }
CSV::Row.new(columns, [], true)
end
def domain_to_row(domain:)
row = []
row[0] = domain.name
row[1] = domain.transfer_code
row[2] = domain.registrant.name
row[3] = domain.registrant.code
row[4] = domain.expire_date
CSV::Row.new([], row)
end
attr_reader :domains, :view
end

View file

@ -1,7 +1,7 @@
- content_for :actions do
= link_to(t(:add), new_admin_invoice_path, class: 'btn btn-primary')
= render 'shared/title', name: t(:invoices)
= render 'search_form'
= render 'admin/invoices/partials/search_form'
.row
.col-md-12

View file

@ -20,4 +20,4 @@
%dd= @invoice.buyer_url
%dt= t(:email)
%dd= @invoice.buyer_email
%dd= @invoice.buyer_email

View file

@ -36,4 +36,4 @@
%dd=@invoice.description
%dt= Invoice.human_attribute_name :reference_no
%dd= @invoice.reference_no
%dd= @invoice.reference_no

View file

@ -29,4 +29,4 @@
%tr
%th.no-border{colspan: 3}
%th= t(:total)
%td= number_to_currency @invoice.total
%td= number_to_currency @invoice.total

View file

@ -16,4 +16,4 @@
%td= payment_order.channel
%td= payment_order.status
%td= payment_order.created_at
%td= payment_order.notes
%td= payment_order.notes

View file

@ -69,10 +69,10 @@
<span class="glyphicon glyphicon-search"></span>
&nbsp;
</button>
<%= link_to t('.download_btn'), admin_invoices_path(format: :csv, params: params.permit!),
"data-toggle" => "tooltip", "data-placement" => "bottom", "title" => t('.download_btn'),
<%= link_to t('admin.invoices.search_form.download_btn'), admin_invoices_path(format: :csv, params: params.permit!),
"data-toggle" => "tooltip", "data-placement" => "bottom", "title" => t('admin.invoices.search_form.download_btn'),
class: 'btn btn-default' %>
<%= link_to t('.reset_btn'), admin_invoices_path, class: 'btn btn-default' %>
<%= link_to t('admin.invoices.search_form.reset_btn'), admin_invoices_path, class: 'btn btn-default' %>
</div>
</div>
<% end %>

View file

@ -35,4 +35,4 @@
%dd= @invoice.seller_email
%dt= t(:issuer)
%dd= @invoice.seller_contact_name
%dd= @invoice.seller_contact_name

View file

@ -20,14 +20,14 @@
= render 'shared/full_errors', object: @invoice
.row
.col-md-6= render 'registrar/invoices/partials/details'
.col-md-6= render 'admin/invoices/partials/details'
.row
.col-md-6= render 'registrar/invoices/partials/seller'
.col-md-6= render 'registrar/invoices/partials/buyer'
.col-md-6= render 'admin/invoices/partials/seller'
.col-md-6= render 'admin/invoices/partials/buyer'
.row
- if @invoice.monthly_invoice
.col-md-12= render 'registrar/invoices/partials/monthly_invoice_items'
- if @invoice.monthly_invoice
.col-md-12= render 'admin/invoices/partials/monthly_invoice_items'
- else
.col-md-12= render 'registrar/invoices/partials/items'
.col-md-12= render 'admin/invoices/partials/items'
.row
.col-md-12= render 'registrar/invoices/partials/payment_orders'
.col-md-12= render 'admin/invoices/partials/payment_orders'

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