Resolve merge errors

This commit is contained in:
Karl Erik Õunapuu 2020-09-02 16:25:34 +03:00
commit 73e9dd6870
817 changed files with 16875 additions and 17443 deletions

View file

@ -1,7 +1,9 @@
version: "2" version: "2"
prepare: prepare:
fetch: fetch:
- "https://raw.githubusercontent.com/internetee/style-guide/master/ruby/.rubocop.yml" - "https://raw.githubusercontent.com/internetee/style-guide/master/.rubocop-ruby.yml"
- url: "https://raw.githubusercontent.com/internetee/style-guide/master/.rubocop-rails.yml"
path: ".rubocop.yml"
plugins: plugins:
brakeman: brakeman:
enabled: true enabled: true
@ -20,27 +22,25 @@ plugins:
enabled: true enabled: true
rubocop: rubocop:
enabled: true enabled: true
channel: rubocop-0-58 channel: rubocop-0-74
checks:
method-lines:
config:
threshold: 40
exclude_patterns: exclude_patterns:
- "app/models/legacy/"
- "app/models/version/" - "app/models/version/"
- "bin/" - "bin/"
- "config/" - "config/"
- "db/" - "db/"
- "lib/action_controller/" - "lib/core_monkey_patches/"
- "lib/core_ext/"
- "lib/daemons/" - "lib/daemons/"
- "lib/gem_ext/" - "lib/gem_monkey_patches/"
- "lib/tasks/api_log.rake" - "lib/tasks/api_log.rake"
- "lib/tasks/bootstrap.rake" - "lib/tasks/bootstrap.rake"
- "lib/tasks/convert.rake"
- "lib/tasks/db.rake" - "lib/tasks/db.rake"
- "lib/tasks/documents.rake" - "lib/tasks/documents.rake"
- "lib/tasks/import.rake"
- "lib/tasks/legal_doc.rake" - "lib/tasks/legal_doc.rake"
- "lib/tasks/statuses.rake"
- "lib/tasks/whois.rake" - "lib/tasks/whois.rake"
- "spec/"
- "test/" - "test/"
- "vendor/" - "vendor/"
- "CHANGELOG.md" - "CHANGELOG.md"

View file

@ -7,7 +7,7 @@ indent_style = space
indent_size = 2 indent_size = 2
max_line_length = 100 max_line_length = 100
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = false insert_final_newline = true
[*.{html,erb}] [*.{html,erb,js}]
indent_size = 4 indent_size = 4

View file

@ -1 +1 @@
registry -global

View file

@ -1 +1 @@
2.4.5 2.6.5

View file

@ -1,8 +0,0 @@
SimpleCov.start 'rails' do
add_filter '/app/models/legacy/'
add_filter '/app/models/version/'
add_filter '/lib/action_controller/'
add_filter '/lib/core_ext/'
add_filter '/lib/daemons/'
add_filter '/lib/gem_ext/'
end

View file

@ -2,7 +2,6 @@ language: ruby
cache: bundler cache: bundler
env: env:
- DB=postgresql - DB=postgresql
bundler_args: --without development staging production
before_install: before_install:
- "wget -N http://chromedriver.storage.googleapis.com/2.43/chromedriver_linux64.zip -P ~/" - "wget -N http://chromedriver.storage.googleapis.com/2.43/chromedriver_linux64.zip -P ~/"
- "unzip ~/chromedriver_linux64.zip -d ~/" - "unzip ~/chromedriver_linux64.zip -d ~/"
@ -10,20 +9,25 @@ before_install:
- "sudo mv -f ~/chromedriver /usr/local/share/" - "sudo mv -f ~/chromedriver /usr/local/share/"
- "sudo chmod +x /usr/local/share/chromedriver" - "sudo chmod +x /usr/local/share/chromedriver"
- "sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver" - "sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver"
- "gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true" - "bundle config set without 'development staging production'"
- "gem install bundler -v '< 2'" - "bundle config set deployment '[secure]'"
before_script: before_script:
- "cp config/application-example.yml config/application.yml" - "cp config/application.yml.sample config/application.yml"
- "cp config/database-travis.yml config/database.yml" - "echo \"openssl_config_path: 'test/fixtures/files/test_ca/openssl.cnf'\" >> config/application.yml"
- "echo \"crl_dir: 'test/fixtures/files/test_ca/crl'\" >> config/application.yml"
- "echo \"crl_path: 'test/fixtures/files/test_ca/crl/crl.pem'\" >> config/application.yml"
- "echo \"ca_cert_path: 'test/fixtures/files/test_ca/certs/ca.crt.pem'\" >> config/application.yml"
- "echo \"ca_key_path: 'test/fixtures/files/test_ca/private/ca.key.pem'\" >> config/application.yml"
- "echo \"ca_key_password: 'password'\" >> config/application.yml"
- "cp config/database_travis.yml config/database.yml"
- "bundle exec rake db:setup:all" - "bundle exec rake db:setup:all"
- "curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter" - "curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter"
- "chmod +x ./cc-test-reporter" - "chmod +x ./cc-test-reporter"
- "./cc-test-reporter before-build" - "./cc-test-reporter before-build"
script:
- "bundle exec rspec"
- "bundle exec rake test"
after_script: after_script:
- "./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT" - "./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT"
script:
- "bundle exec rails test test/*"
services: services:
- postgresql - postgresql
addons: addons:

View file

@ -1,3 +1,397 @@
01.09.2020
* Removed some unused settings from admin [#1668](https://github.com/internetee/registry/issues/1668)
27.08.2020
* Fixed internal error in domain history [#1663](https://github.com/internetee/registry/issues/1663)
* Second lvl zone records return now empty string for dnskey values [#1665](https://github.com/internetee/registry/issues/1665)
26.08.2020
* Fixed website url display issue in PDF invoices [#1188](https://github.com/internetee/registry/issues/1188)
* Added error logging for missing cert_path [#1420](https://github.com/internetee/registry/pull/1420)
* Refactored settings store mechanism [#1629](https://github.com/internetee/registry/issues/1629)
* Registrant API now returns users' business contacts [#1642](https://github.com/internetee/registry/issues/1642)
14.08.2020
* Added handling of second lvl zoness managed by the registry in whois records [#1661](https://github.com/internetee/registry/issues/1661)
13.08.2020
* Removed keystore gem and replaced LHV JKS with PKCS12 [#1645](https://github.com/internetee/registry/issues/1645)
11.08.2020
* Fixed postal address saving bug with disabled address processing [#1650](https://github.com/internetee/registry/issues/1650)
07.08.2020
* Restored creator and updator strings to contacts and related object records [#1636](https://github.com/internetee/registry/issues/1636)
* Security gem updates: sdoc to 1.1 and json to 2.3.1 [#1657](https://github.com/internetee/registry/pull/1657)
04.08.2020
* Fixed registrant verification for domain delete [#1631](https://github.com/internetee/registry/issues/1631)
* Fixed domain transfer issue when one person was present in the same role more than once (different objects) [#1651](https://github.com/internetee/registry/issues/1651)
03.08.2020
* Fixed 0 vat issue with invoices sent to Directo [#1647](https://github.com/internetee/registry/issues/1647)
17.07.2020
* Added turemail gem for validating email addresses syntactically and on MX record level [#297](https://github.com/internetee/registry/issues/297)
15.07.2020
* Reapplied race condition fix after fixing the data in prod env [#1612](https://github.com/internetee/registry/issues/1612)
07.07.2020
* Fixed legaldoc validation [#1634](https://github.com/internetee/registry/issues/1634)
* Disabled collection cashe versioning [#1637](https://github.com/internetee/registry/pull/1637)
03.07.2020
* 1-character domains are now valid but blocked by default [#1625](https://github.com/internetee/registry/issues/1625)
02.07.2020
* Adding legaldoc to domain:delete is now optional [#1624](https://github.com/internetee/registry/issues/1624)
* Setting to make legaldoc functionality optional [#1623](https://github.com/internetee/registry/issues/1623)
01.07.2020
* Reverted race condition fix due to data issues in production (#1612) [#1622](https://github.com/internetee/registry/pull/1622)
* Added legaldoc opt-out option for approved registrars [#1620](https://github.com/internetee/registry/issues/1620)
29.06.2020
* Bumped rack to 2.2.3 [#1618](https://github.com/internetee/registry/pull/1618)
* Actionpack security update to 6.0.3.2 [#1619](https://github.com/internetee/registry/pull/1619)
26.06.2020
* Fixed race condition in domain update by adding new db constratints [#1612](https://github.com/internetee/registry/issues/1612)
* Refactored contact validation [#1617](https://github.com/internetee/registry/pull/1617)
19.06.2020
* Regsitrant API returns now DNSSEC info [#1613](https://github.com/internetee/registry/pull/1613)
* Updated domain expiration email notification texts [#1614](https://github.com/internetee/registry/pull/1614)
15.06.2020
* Added contact email to registrant API [#1611](https://github.com/internetee/registry/pull/1611)
12.06.2020
* Extracted Xml deserializing from EPP Contact and Domain classes [#1601](https://github.com/internetee/registry/pull/1601)
* Fixed whois data update issue with child object updates [#1604](https://github.com/internetee/registry/issues/1604)
11.06.2020
* Auction API returns json on error [#1605](https://github.com/internetee/registry/issues/1605)
* Fixed account activity index in admin [#1606](https://github.com/internetee/registry/issues/1606)
08.06.2020
* Bumped websocket-extensions to 0.1.5 [#1602](https://github.com/internetee/registry/pull/1602)
04.06.2020
* Moved dev config to sample file [#1599](https://github.com/internetee/registry/pull/1599)
* Post Rails6 upgrade fixes [#1598](https://github.com/internetee/registry/pull/1598)
03.06.2020
* Upgraded Rails to 6.0.3 [#1593](https://github.com/internetee/registry/pull/1593)
02.06.2020
* Fixed registration deadline format for whois/restwhois [#1595](https://github.com/internetee/registry/pull/1595)
01.06.2020
* Improved error handling in case legal doc is not found for downloading [#1452](https://github.com/internetee/registry/issues/1452)
29.05.2020
* Bump kaminari to 1.2.1 [#1592](https://github.com/internetee/registry/pull/1592)
28.05.2020
* REPP returns list of disputed domains [#1588](https://github.com/internetee/registry/issues/1588)
* Updated Directo gem [#1590](https://github.com/internetee/registry/pull/1590)
* Updated LHV gem [#1591](https://github.com/internetee/registry/pull/1591)
25.05.2020
* Fixed registrant change verification bug for disputed domains [#1586](https://github.com/internetee/registry/issues/1586)
22.05.2020
* New solution for managing domains with effective dispute commitee decision [#269](https://github.com/internetee/registry/issues/269)
* Bump puma from 4.3.5 [#1585](https://github.com/internetee/registry/pull/1585)
* Run all CI tests [#1584](https://github.com/internetee/registry/pull/1584)
21.05.2020
* Fixed contact view access bug in registrant [#1527](https://github.com/internetee/registry/pull/1527)
* REPP returns list of domains currently at auction [#1582](https://github.com/internetee/registry/pull/1582)
18.05.2020
* REPP returns list of reserved and blocked domains [#1569](https://github.com/internetee/registry/issues/1569)
14.05.2020
* Deleted certificates are now revoked first [#952](https://github.com/internetee/registry/issues/952)
11.05.2020
* Auction process due dates are now available over whois and rest-whois [#1201](https://github.com/internetee/registry/issues/1201)
30.04.2020
* Fix for internal error on opening domain history with legacy id record [#1576](https://github.com/internetee/registry/issues/1576)
27.04.2020
* Downgrade SimpleCov to 0.17 due to incompatibiilty with CodeClimate [#1575](https://github.com/internetee/registry/pull/1575)
17.04.2020
* Webinterfaces have now clickable version string pointing to the latest deployed commit in github [#1345](https://github.com/internetee/registry/pull/1345)
15.04.2020
* Updated Rails to 5.2 and fixed acitionview security issue [#1568](https://github.com/internetee/registry/issues/1568)
25.03.2020
* Implemented Directo gem [#1547](https://github.com/internetee/registry/pull/1547)
11.03.2020
* Fixed glue record issues when using 2nd level domain as host [#1562](https://github.com/internetee/registry/issues/1562)
10.03.2020
* Updated lhv, e-invoice & company_register gem due to security updates [#1564](https://github.com/internetee/registry/pull/1564)
06.03.2020
* Record payment method and failed payments [#1422](https://github.com/internetee/registry/issues/1422)
04.03.2020
* Bump Puma to 4.3.3 [#1557](https://github.com/internetee/registry/pull/1557)
03.03.2020
* Admin: fixed import of th6 bank statement [#1551](https://github.com/internetee/registry/issues/1551)
02.03.2020
* Registrar: fixed statuses based contact filtering [#1004](https://github.com/internetee/registry/issues/1004)
28.02.2020
* Registrar: fixed account switching [#1535](https://github.com/internetee/registry/issues/1535)
27.02.2020
* Registrar: fixed the verified checkbox bug that did not change the element value to yes in epp request [#1540](https://github.com/internetee/registry/issues/1540)
* Ruby version update to 2.6.5 [#1545](https://github.com/internetee/registry/pull/1545)
26.02.2020
* Registrar: added an option to remove clientHold status [#1481](https://github.com/internetee/registry/issues/1481)
* Admin: fixed domain status removal issue [#1543](https://github.com/internetee/registry/issues/1543)
* Implemented consistent and automated data migrations [#1298](https://github.com/internetee/registry/issues/1298)
20.02.2020
* E-invoice sending to Que to manage resending in case of an error [#1509](https://github.com/internetee/registry/issues/1509)
* Check to make sure all monthly invoices fit in available invoice number range [#277](https://github.com/internetee/registry/issues/277)
* Disabled aurbreak performance monitoring [#1534](https://github.com/internetee/registry/pull/1534)
14.02.2020
* Fixed Papertrail warnings [#1530](https://github.com/internetee/registry/issues/1530)
12.02.2020
* Fixed papertrails double recording issue [#1526](https://github.com/internetee/registry/issues/1526)
* Requests to Directo are now saved for both credit and monthly invoices [#344](https://github.com/internetee/registry/issues/344)
10.02.2020
* Resolved Money gem deprecation warning and silenced all warnings due plan to replace papertrail [#1522](https://github.com/internetee/registry/pull/1522)
06.02.2020
* Permit & turn ActiveController::Parameters to hash on domain create [#1516](https://github.com/internetee/registry/issues/1516)
05.02.2020
* Ruby version upgrade to 2.6.3 [#846](https://github.com/internetee/registry/issues/846)
* Added retries & raise to connect api to handle timeouts [#1474](https://github.com/internetee/registry/issues/1474)
* Added logging of XML if there is NoMethodError#text on xml data fields [#1475](https://github.com/internetee/registry/issues/1475)
04.02.2020
* Fixed bug that allowed bypassing blocked domain validation using punycode [#1142](https://github.com/internetee/registry/issues/1142)
* SimpleIDN gem update to 0.0.9 [#1508](https://github.com/internetee/registry/pull/1508)
31.01.2020
* Instant payments marks specific invoice as paid [#1500](https://github.com/internetee/registry/issues/1500)
* Sending invoice payment date to accounting [#1416](https://github.com/internetee/registry/issues/1416)
29.01.2020
* Fixed the invoice binding bug where process failed if registrar tried to load a sum that they have used before [#1496](https://github.com/internetee/registry/issues/1496)
28.01.2020
* Registrar: fixed sorting of domain view [#1461](https://github.com/internetee/registry/issues/1461)
* clientHold status is now set once instead of resetting it every time the job is run [#1480](https://github.com/internetee/registry/issues/1480)
27.01.2020
* Admin: fixed history view for domains with legacy id [#1489](https://github.com/internetee/registry/issues/1489)
23.01.2020
* Payment invoice matching by looking for ref nr in description field [#1415](https://github.com/internetee/registry/issues/1415)
22.01.2020
* ForceDelete poll messages with outzone and purge dates [#1478](https://github.com/internetee/registry/issues/1478)
21.01.2020
* Registrant change cancels automatically force delete process [#1479](https://github.com/internetee/registry/issues/1479)
20.01.2020
* ForceDelete email notifications are sent to all contacts + info and domain@domain [#1477](https://github.com/internetee/registry/issues/1477)
18.01.2020
* New ForceDelete procedure [#1428](https://github.com/internetee/registry/issues/1428)
16.01.2020
* Added tests for registrant verification [#1430](https://github.com/internetee/registry/pull/1430)
14.01.2020
* removed authinfo element from contact:info response for non-sponsoring registrars [#1446](https://github.com/internetee/registry/issues/1446)
13.01.2020
* resolved internal error on registrant confirmation [#1468](https://github.com/internetee/registry/issues/1468)
10.01.2020
* updated ForceDelete email templates according new regulation [#1466](https://github.com/internetee/registry/issues/1466)
* regenerated WHOIS db schema [#1436](https://github.com/internetee/registry/pull/1436)
09.01.2020
* serverForceDelete status does not block removing clientHold status [#1462](https://github.com/internetee/registry/pull/1462)
06.01.2020
* Updated e-invoice gem [#1456](https://github.com/internetee/registry/pull/1456)
* Bumped rack gem to 2.0.8 [#1448](https://github.com/internetee/registry/pull/1448)
03.01.2020
* Added an option for registrars to add and remove clientHold status on domains [#1454](https://github.com/internetee/registry/pull/1454)
* Fixed contact view internal error in admin [#1458](https://github.com/internetee/registry/issues/1458)
27.12.2019
* Records in registrant_verifications are now archived by PaperTrail [#1425](https://github.com/internetee/registry/issues/1425)
16.12.2019
* Bump puma from 4.2.1 to 4.3.1 [#1437](https://github.com/internetee/registry/pull/1437)
* Refactored API user management [#1435](https://github.com/internetee/registry/pull/1435)
* Ignoring legacy database columns at ActiveRecord level [#1377](https://github.com/internetee/registry/issues/1377)
* Removed Ruby version from Travis config and let it use .ruby-version [#1441](https://github.com/internetee/registry/pull/1441)
* Removed `fill_ident_country` postgresql function as unused [#1439](https://github.com/internetee/registry/pull/1439)
12.12.2019
* Updated e-invoice gem [#1429](https://github.com/internetee/registry/pull/1429)
* Upgraded bundler to 2.0.2 [#1433](https://github.com/internetee/registry/pull/1433)
* Set not null constraint on contact.name db column [#1417](https://github.com/internetee/registry/pull/1417)
* Removed domain name from registrant_verifications table [#1431](https://github.com/internetee/registry/pull/1431)
19.11.2019
* Updated Rails to 5.0.7 [#377](https://github.com/internetee/registry/issues/377)
15.11.2019
* Restored EPP exception logging to syslog [#1371](https://github.com/internetee/registry/issues/1371)
11.11.2019
* Removed code for displaying errors in nameserver and dnskey data as unused [#1411](https://github.com/internetee/registry/pull/1411)
07.11.2019
* Fixed domain details view in admin where admin and tech contacts were marked as invalid with Rails 5 [#1413](https://github.com/internetee/registry/pull/1413)
06.11.2019
* Fixed account activity form filter and csv download issues in admin and registrar [#1410](https://github.com/internetee/registry/pull/1410)
05.11.2019
* Moved gem extensions to proper directory and renamed the dirs to "moneky patces" to improve readability [#1406](https://github.com/internetee/registry/pull/1406)
04.11.2019
* Tuned kaminari gem to solve pagination issues [#1405](https://github.com/internetee/registry/pull/1405)
01.11.2019
* Typo fixes for #1352 [#1396](https://github.com/internetee/registry/pull/1396)
* Updated que gem to 0.14.3 and que-web gem to 0.7.2 [#1404](https://github.com/internetee/registry/pull/1404)
31.10.2019
* Updated domain_name gem to 0.5.20190701 [#1400](https://github.com/internetee/registry/pull/1400)
* Updated webmock gem to 3.7.6 [#1401](https://github.com/internetee/registry/pull/1401)
* Improved setup and seed [#1352](https://github.com/internetee/registry/pull/1352)
* Removed unimplemented keyrelay code [#715](https://github.com/internetee/registry/issues/715)
* Removed uuidtools gem [#1390](https://github.com/internetee/registry/pull/1390)
* Removed some unneeded code [#1397](https://github.com/internetee/registry/pull/1397)
* Removed eis_trusted_proxies setting [#1398](https://github.com/internetee/registry/pull/1398)
28.10.2019
* Updated kaminari gem to 1.1.1 [#1392](https://github.com/internetee/registry/pull/1392)
* Downgraded minitest to 5.10.3 due to incompatibility with Rails 5.0 [#1387](https://github.com/internetee/registry/pull/1387)
* New db constaints to invoices and invoice_items tables [#1388](https://github.com/internetee/registry/pull/1388)
* Removed buggy code for contact details' fast access in regitrar portal [#1386](https://github.com/internetee/registry/pull/1386)
23.10.2019
* Updated haml gem to 5.1.2 (CVE-2017-1002201) [#1384](https://github.com/internetee/registry/pull/1384)
* Removed bullet gem [#378](https://github.com/internetee/registry/issues/378)
* Removed duplicate route from admin [#1375](https://github.com/internetee/registry/pull/1375)
21.10.2019
* Tuned PDFkit gem [#1367](https://github.com/internetee/registry/pull/1367)
* Removed some dead code [#1370](https://github.com/internetee/registry/pull/1370)
17.10.2019
* Implemented properl handling of contact transfer requests [#1363](https://github.com/internetee/registry/pull/1363)
* Test environment tuning [#1366](https://github.com/internetee/registry/pull/1366)
16.10.2019
* Contact and domain list download in portals changed - buttons in stead of dropdown [#1360](https://github.com/internetee/registry/pull/1360)
* limited epp routes [#1364](https://github.com/internetee/registry/pull/1364)
11.10.2019
* Fixed mailer previews for couple email templates [#1342](https://github.com/internetee/registry/pull/1342)
* Updated ransack gem to 1.8 [#1357](https://github.com/internetee/registry/pull/1357)
* Removed old import rake task [#1355](https://github.com/internetee/registry/pull/1355)
10.10.2019
* Added DB constraints for reserved and blocked tables [#1338](https://github.com/internetee/registry/pull/1338)
08.10.2019
* Removed unused epp routes [#1335](https://github.com/internetee/registry/pull/1335)
* Removed Rspec and coverted specs to tests [#1336](https://github.com/internetee/registry/pull/1336)
* Added test for EPP hello request [#1337](https://github.com/internetee/registry/pull/1337)
* Removed unused csr and crt columns from user table [#264](https://github.com/internetee/registry/issues/264)
* Bump rubyzip from 1.2.2 to 1.3.0 [#1349](https://github.com/internetee/registry/pull/1349)
07.10.2019
* Clarified reference to proper phone nr format in EPP spec [#1343](https://github.com/internetee/registry/pull/1343)
20.09.2019
* Fixed error on domain transfer with invalid code [#686](https://github.com/internetee/registry/issues/686)
* EPP exceptions are now sent to Errbit [#539](https://github.com/internetee/registry/issues/539)
* Updated jquery-rails gem to 4.3.5 [#1322](https://github.com/internetee/registry/pull/1322)
* Added EPP renew tests [#1326](https://github.com/internetee/registry/pull/1326)
17.09.2019
* Fixed error messages on deletind deletecandidate domains [#718](https://github.com/internetee/registry/issues/718)
* Removed html2haml gem [#1316](https://github.com/internetee/registry/pull/1316)
16.09.2019
* Updated coffee-rails gem to 4.2 [#1320](https://github.com/internetee/registry/pull/1320)
* Updated data_migrate gem to 5.3.2 [#1321](https://github.com/internetee/registry/pull/1321)
* Replaced unused haml-rails gem with haml [#1315](https://github.com/internetee/registry/pull/1315)
* Hid some methods [#1318](https://github.com/internetee/registry/pull/1318)
13.09.2019
* Fixed bug where glue records were identified on partial string match with the domain name [#1291](https://github.com/internetee/registry/issues/1291)
* Removed 1 second delay on erroneous epp query responses [#1299](https://github.com/internetee/registry/pull/1299)
* Autoupdated Devise gem to 4.7.1 [#1304](https://github.com/internetee/registry/pull/1304)
* Updated Airbrake gem to 9.4.3 and tuned the configuration [#1297](https://github.com/internetee/registry/pull/1297)
* Updated cancancan gem to 3.0.1 [#1300](https://github.com/internetee/registry/pull/1300)
* Updated filenames to follow Ruby name convention [#1295](https://github.com/internetee/registry/pull/1295)
* Removed unused jbuilder gem [#1311](https://github.com/internetee/registry/pull/1311)
* Removed mod_epp specific X-EPP-Returncode EPP response header [#1301](https://github.com/internetee/registry/pull/1301)
* Removed a dublicate test [#1302](https://github.com/internetee/registry/pull/1302)
* Removed disabled and unnecessary CSRF protection [#1305](https://github.com/internetee/registry/pull/1305)
* Introduced modules [#1312](https://github.com/internetee/registry/pull/1312)
09.09.2019
* Upgrade Ruby to 2.4.7 [#1289](https://github.com/internetee/registry/pull/1289)
05.09.2019
* Update hashdiff gem to 1.0.0 [#1287](https://github.com/internetee/registry/pull/1287)
03.09.2019
* Updated Ruby to version 2.5.5 [#1273](https://github.com/internetee/registry/pull/1273)
* Figaro cleanup [#1272](https://github.com/internetee/registry/pull/1272)
* Removed deprecated testcase class [#1277](https://github.com/internetee/registry/pull/1277)
27.08.2019
* Added some new database constraints [#1265](https://github.com/internetee/registry/pull/1265)
26.08.2019
* Introduced automatic payment processing using LHV Connect [#1232](https://github.com/internetee/registry/issues/1232)
* removed unused script [#1261](https://github.com/internetee/registry/pull/1261)
* removed unused factory [#1262](https://github.com/internetee/registry/pull/1262)
* removed unused seller_it column from invoices db table [#1264](https://github.com/internetee/registry/pull/1264)
* removed unused rake tasks [#1268](https://github.com/internetee/registry/pull/1268)
21.08.2019
* Nokogiri update to 1.10.4 (CVE-2019-5477) [#1266](https://github.com/internetee/registry/pull/1266)
08.07.2019
* Invoices are not delivered to e-invoice provider when registrar has no billing email [#1255](https://github.com/internetee/registry/issues/1255)
28.06.2019 28.06.2019
* E-invoicing with every generated invoice [#1222](https://github.com/internetee/registry/issues/1222) * E-invoicing with every generated invoice [#1222](https://github.com/internetee/registry/issues/1222)

View file

@ -1,5 +1,4 @@
FROM internetee/ruby:2.4 FROM internetee/ruby:2.6-buster
MAINTAINER maciej.szlosarczyk@internet.ee
RUN mkdir -p /opt/webapps/app/tmp/pids RUN mkdir -p /opt/webapps/app/tmp/pids
WORKDIR /opt/webapps/app WORKDIR /opt/webapps/app

90
Gemfile
View file

@ -1,15 +1,9 @@
# Use https only for accessing github
# https://github.com/bundler/bundler/pull/3447
git_source(:github) do |repo_name|
repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
"https://github.com/#{repo_name}.git"
end if Bundler::VERSION < '2'
source 'https://rubygems.org' source 'https://rubygems.org'
# core # core
gem 'iso8601', '0.8.6' # for dates and times gem 'bootsnap', '>= 1.1.0', require: false
gem 'rails', '4.2.11.1' # when update, all initializers eis_custom files needs check/update gem 'iso8601', '0.12.1' # for dates and times
gem 'rails', '~> 6.0'
gem 'rest-client' gem 'rest-client'
gem 'uglifier' gem 'uglifier'
@ -17,50 +11,37 @@ gem 'uglifier'
gem 'figaro', '1.1.1' gem 'figaro', '1.1.1'
# model related # model related
gem 'pg', '0.19.0' gem 'activerecord-import'
gem 'ransack', '1.5.1' # for searching gem 'paper_trail', '~> 10.3'
gem 'pg', '1.2.2'
# 1.8 is for Rails < 5.0
gem 'ransack', '~> 2.3'
gem 'truemail', '~> 1.7' # validates email by regexp, mail server existence and address existence
gem 'validates_email_format_of', '1.6.3' # validates email against RFC 2822 and RFC 3696 gem 'validates_email_format_of', '1.6.3' # validates email against RFC 2822 and RFC 3696
gem 'paper_trail', '~> 4.0'
# 0.7.3 is the latest for Rails 4.2, however, it is absent on Rubygems server # 0.7.3 is the latest for Rails 4.2, however, it is absent on Rubygems server
# https://github.com/huacnlee/rails-settings-cached/issues/165 # https://github.com/huacnlee/rails-settings-cached/issues/165
gem 'rails-settings-cached', '0.7.2'
# html-xml
gem 'haml-rails', '0.9.0' # haml for views
gem 'nokogiri' gem 'nokogiri'
# style # style
gem 'bootstrap-sass', '~> 3.4' gem 'bootstrap-sass', '~> 3.4'
gem 'sass-rails', '5.0.6' # sass style gem 'coffee-rails', '>= 5.0'
gem 'jquery-rails'
# js
gem 'coffee-rails', '4.1.0' # coffeescript support
gem 'jquery-rails', '4.0.4' # jquery
gem 'selectize-rails', '0.12.1' # include selectize.js for select gem 'selectize-rails', '0.12.1' # include selectize.js for select
gem 'kaminari'
# view helpers
gem 'kaminari', '0.16.3' # pagination
gem 'coderay', '1.1.0' # xml console visualize gem 'coderay', '1.1.0' # xml console visualize
gem 'sass-rails'
gem 'select2-rails', '3.5.9.3' # for autocomplete gem 'select2-rails', '3.5.9.3' # for autocomplete
gem 'cancancan'
# rights gem 'devise', '~> 4.7'
gem 'cancancan', '1.11.0' # autharization
gem 'devise', '~> 4.0'
gem 'grape' gem 'grape'
gem 'jbuilder', '2.2.16' # json api
# registry specfic # registry specfic
gem 'data_migrate', '~> 6.1'
gem 'isikukood' # for EE-id validation gem 'isikukood' # for EE-id validation
gem 'simpleidn', '0.0.7' # For punycode gem 'simpleidn', '0.1.1' # For punycode
gem 'money-rails' gem 'money-rails'
# deploy
gem 'data_migrate',
github: 'internetee/data-migrate',
ref: '35d22b09ff37a4e9d61ab326ad5d8eb0edf1fc81'
gem 'whenever', '0.9.4', require: false gem 'whenever', '0.9.4', require: false
# country listing # country listing
@ -73,50 +54,43 @@ gem 'digidoc_client',
ref: '1645e83a5a548addce383f75703b0275c5310c32' ref: '1645e83a5a548addce383f75703b0275c5310c32'
gem 'epp', '1.5.0', github: 'internetee/epp' gem 'epp', github: 'internetee/epp', branch: :master
gem 'epp-xml', '1.1.0', github: 'internetee/epp-xml' gem 'epp-xml', '1.1.0', github: 'internetee/epp-xml'
gem 'uuidtools', '2.1.5' # For unique IDs (used by the epp gem) gem 'que'
# que
gem 'que', '0.10.0'
gem 'daemons-rails', '1.2.1' gem 'daemons-rails', '1.2.1'
gem 'que-web', '0.4.0' gem 'que-web'
# for importing legacy db
gem 'activerecord-import', '0.7.0' # for inserting dummy data
gem 'pdfkit' gem 'pdfkit'
gem 'jquery-ui-rails', '5.0.5' gem 'jquery-ui-rails', '5.0.5'
gem 'active_model-errors_details' # Backport from Rails 5, https://github.com/rails/rails/pull/18322
gem 'airbrake' gem 'airbrake'
gem 'company_register', github: 'internetee/company_register', branch: :master gem 'company_register', github: 'internetee/company_register', branch: :master
gem 'e_invoice', github: 'internetee/e_invoice', branch: :master gem 'e_invoice', github: 'internetee/e_invoice', branch: :master
gem 'lhv', github: 'internetee/lhv', branch: 'master'
gem 'domain_name'
gem 'haml', '~> 5.0'
gem 'wkhtmltopdf-binary', '~> 0.12.5.1'
gem 'directo', github: 'internetee/directo', branch: 'master'
group :development do group :development do
# deploy # deploy
gem 'listen', '3.2.1'
gem 'mina', '0.3.1' # for fast deployment gem 'mina', '0.3.1' # for fast deployment
end end
group :development, :test do group :development, :test do
gem 'factory_bot_rails'
gem 'capybara'
gem 'rspec-rails', '~> 3.6'
gem 'selenium-webdriver'
# debug
gem 'pry', '0.10.1' gem 'pry', '0.10.1'
gem 'bullet', '4.14.7' # for finding database optimizations
gem 'html2haml', '2.1.0'
gem 'sdoc', '0.4.1' # bundle exec rake doc:rails generates the API under doc/api.
gem 'railroady', '1.3.0' # to generate database diagrams gem 'railroady', '1.3.0' # to generate database diagrams
gem 'autodoc' gem 'autodoc'
gem 'puma' gem 'puma'
gem 'sdoc', '~> 1.1'
end end
group :test do group :test do
gem 'capybara'
gem 'database_cleaner' gem 'database_cleaner'
gem 'simplecov', require: false gem 'minitest', '~> 5.14'
gem 'simplecov', '0.17.1', require: false # CC last supported v0.17
gem 'webdrivers'
gem 'webmock' gem 'webmock'
end end

View file

@ -1,6 +1,6 @@
GIT GIT
remote: https://github.com/internetee/company_register.git remote: https://github.com/internetee/company_register.git
revision: da7130542304fc543c90d54cd037d019a777c526 revision: 86d691997aa7def9f86d88f6c92cabb86cd65487
branch: master branch: master
specs: specs:
company_register (0.1.0) company_register (0.1.0)
@ -8,16 +8,17 @@ GIT
savon savon
GIT GIT
remote: https://github.com/internetee/data-migrate.git remote: https://github.com/internetee/directo.git
revision: 35d22b09ff37a4e9d61ab326ad5d8eb0edf1fc81 revision: 8ff8a382d004ffb85722a6a7a68a020bd4d7159b
ref: 35d22b09ff37a4e9d61ab326ad5d8eb0edf1fc81 branch: master
specs: specs:
data_migrate (1.3.0) directo (1.0.1)
rails (>= 4.1.0) money (~> 6.13)
nokogiri (~> 1.10)
GIT GIT
remote: https://github.com/internetee/e_invoice.git remote: https://github.com/internetee/e_invoice.git
revision: 917318bd546322408b83567745375c998619c926 revision: b374ffd7be77b559b30c7a0210dc0df5ac3ed723
branch: master branch: master
specs: specs:
e_invoice (0.1.0) e_invoice (0.1.0)
@ -27,20 +28,30 @@ GIT
GIT GIT
remote: https://github.com/internetee/epp-xml.git remote: https://github.com/internetee/epp-xml.git
revision: 5dd542e67ef26d58365f30e553254d6db809277d revision: 27959f8cb244ea5eabaeeee747984988b454e840
specs: specs:
epp-xml (1.1.0) epp-xml (1.1.0)
activesupport (~> 4.1) activesupport (>= 4.1)
builder (~> 3.2) builder (~> 3.2)
GIT GIT
remote: https://github.com/internetee/epp.git remote: https://github.com/internetee/epp.git
revision: 1a50f2144f15a2d975337e56fb1ccaba5d956e9d revision: af7cefda37ac81d14b1d12641cde410776082d59
branch: master
specs: specs:
epp (1.5.0) epp (1.5.0)
hpricot hpricot
libxml-ruby libxml-ruby
GIT
remote: https://github.com/internetee/lhv.git
revision: 1825240b3bf8b262418cc6c8ef7ed1aba386dd7d
branch: master
specs:
lhv (0.1.0)
logger
nokogiri
GIT GIT
remote: https://github.com/tarmotalu/digidoc_client.git remote: https://github.com/tarmotalu/digidoc_client.git
revision: 1645e83a5a548addce383f75703b0275c5310c32 revision: 1645e83a5a548addce383f75703b0275c5310c32
@ -56,74 +67,87 @@ GIT
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actionmailer (4.2.11.1) actioncable (6.0.3.2)
actionpack (= 4.2.11.1) actionpack (= 6.0.3.2)
actionview (= 4.2.11.1) nio4r (~> 2.0)
activejob (= 4.2.11.1) websocket-driver (>= 0.6.1)
actionmailbox (6.0.3.2)
actionpack (= 6.0.3.2)
activejob (= 6.0.3.2)
activerecord (= 6.0.3.2)
activestorage (= 6.0.3.2)
activesupport (= 6.0.3.2)
mail (>= 2.7.1)
actionmailer (6.0.3.2)
actionpack (= 6.0.3.2)
actionview (= 6.0.3.2)
activejob (= 6.0.3.2)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 2.0)
actionpack (4.2.11.1) actionpack (6.0.3.2)
actionview (= 4.2.11.1) actionview (= 6.0.3.2)
activesupport (= 4.2.11.1) activesupport (= 6.0.3.2)
rack (~> 1.6) rack (~> 2.0, >= 2.0.8)
rack-test (~> 0.6.2) rack-test (>= 0.6.3)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.2.0)
actionview (4.2.11.1) actiontext (6.0.3.2)
activesupport (= 4.2.11.1) actionpack (= 6.0.3.2)
activerecord (= 6.0.3.2)
activestorage (= 6.0.3.2)
activesupport (= 6.0.3.2)
nokogiri (>= 1.8.5)
actionview (6.0.3.2)
activesupport (= 6.0.3.2)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubi (~> 1.4)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3) rails-html-sanitizer (~> 1.1, >= 1.2.0)
active_model-errors_details (1.3.1) activejob (6.0.3.2)
activemodel (>= 3.2.13, < 5.0.0) activesupport (= 6.0.3.2)
activesupport globalid (>= 0.3.6)
activejob (4.2.11.1) activemodel (6.0.3.2)
activesupport (= 4.2.11.1) activesupport (= 6.0.3.2)
globalid (>= 0.3.0) activerecord (6.0.3.2)
activemodel (4.2.11.1) activemodel (= 6.0.3.2)
activesupport (= 4.2.11.1) activesupport (= 6.0.3.2)
builder (~> 3.1) activerecord-import (1.0.5)
activerecord (4.2.11.1) activerecord (>= 3.2)
activemodel (= 4.2.11.1) activestorage (6.0.3.2)
activesupport (= 4.2.11.1) actionpack (= 6.0.3.2)
arel (~> 6.0) activejob (= 6.0.3.2)
activerecord-import (0.7.0) activerecord (= 6.0.3.2)
activerecord (>= 3.0) marcel (~> 0.3.1)
activesupport (4.2.11.1) activesupport (6.0.3.2)
i18n (~> 0.7) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1) minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1) tzinfo (~> 1.1)
addressable (2.6.0) zeitwerk (~> 2.2, >= 2.2.2)
public_suffix (>= 2.0.2, < 4.0) addressable (2.7.0)
airbrake (6.0.0) public_suffix (>= 2.0.2, < 5.0)
airbrake-ruby (~> 2.0) airbrake (10.0.5)
airbrake-ruby (2.0.0) airbrake-ruby (~> 4.13)
airbrake-ruby (4.15.0)
rbtree3 (~> 0.5)
akami (1.3.1) akami (1.3.1)
gyoku (>= 0.4.0) gyoku (>= 0.4.0)
nokogiri nokogiri
arel (6.0.4) autodoc (0.7.4)
autodoc (0.6.0)
actionpack actionpack
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
rspec rspec
autoprefixer-rails (9.4.8) autoprefixer-rails (9.8.4)
execjs execjs
axiom-types (0.1.1) bcrypt (3.1.13)
descendants_tracker (~> 0.0.4) bootsnap (1.4.6)
ice_nine (~> 0.11.0) msgpack (~> 1.0)
thread_safe (~> 0.3, >= 0.3.1)
bcrypt (3.1.12)
bootstrap-sass (3.4.1) bootstrap-sass (3.4.1)
autoprefixer-rails (>= 5.2.1) autoprefixer-rails (>= 5.2.1)
sassc (>= 2.0.0) sassc (>= 2.0.0)
builder (3.2.3) builder (3.2.4)
bullet (4.14.7) cancancan (3.1.0)
activesupport (>= 3.0.0) capybara (3.33.0)
uniform_notifier (~> 1.9.0)
cancancan (1.11.0)
capybara (3.22.0)
addressable addressable
mini_mime (>= 0.1.3) mini_mime (>= 0.1.3)
nokogiri (~> 1.8) nokogiri (~> 1.8)
@ -131,248 +155,263 @@ GEM
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
regexp_parser (~> 1.5) regexp_parser (~> 1.5)
xpath (~> 3.2) xpath (~> 3.2)
childprocess (0.9.0) childprocess (3.0.0)
ffi (~> 1.0, >= 1.0.11)
chronic (0.10.2) chronic (0.10.2)
coderay (1.1.0) coderay (1.1.0)
coercible (1.0.0) coffee-rails (5.0.0)
descendants_tracker (~> 0.0.1)
coffee-rails (4.1.0)
coffee-script (>= 2.2.0) coffee-script (>= 2.2.0)
railties (>= 4.0.0, < 5.0) railties (>= 5.2.0)
coffee-script (2.4.1) coffee-script (2.4.1)
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.12.2) coffee-script-source (1.12.2)
concurrent-ruby (1.1.5) concurrent-ruby (1.1.6)
countries (3.0.0) countries (3.0.1)
i18n_data (~> 0.8.0) i18n_data (~> 0.10.0)
sixarm_ruby_unaccent (~> 1.1) sixarm_ruby_unaccent (~> 1.1)
unicode_utils (~> 1.4) unicode_utils (~> 1.4)
crack (0.4.3) crack (0.4.3)
safe_yaml (~> 1.0.0) safe_yaml (~> 1.0.0)
crass (1.0.4) crass (1.0.6)
daemons (1.2.4) daemons (1.3.1)
daemons-rails (1.2.1) daemons-rails (1.2.1)
daemons daemons
multi_json (~> 1.0) multi_json (~> 1.0)
database_cleaner (1.6.1) data_migrate (6.3.0)
descendants_tracker (0.0.4) rails (>= 5.0)
thread_safe (~> 0.3, >= 0.3.1) database_cleaner (1.8.5)
devise (4.6.1) devise (4.7.2)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 4.1.0, < 6.0) railties (>= 4.1.0)
responders responders
warden (~> 1.2.3) warden (~> 1.2.3)
diff-lcs (1.3) diff-lcs (1.4.4)
docile (1.3.1) docile (1.3.2)
domain_name (0.5.20170404) domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
equalizer (0.0.11) dry-configurable (0.11.6)
concurrent-ruby (~> 1.0)
dry-core (~> 0.4, >= 0.4.7)
dry-equalizer (~> 0.2)
dry-container (0.7.2)
concurrent-ruby (~> 1.0)
dry-configurable (~> 0.1, >= 0.1.3)
dry-core (0.4.9)
concurrent-ruby (~> 1.0)
dry-equalizer (0.3.0)
dry-inflector (0.2.0)
dry-logic (1.0.6)
concurrent-ruby (~> 1.0)
dry-core (~> 0.2)
dry-equalizer (~> 0.2)
dry-types (1.4.0)
concurrent-ruby (~> 1.0)
dry-container (~> 0.3)
dry-core (~> 0.4, >= 0.4.4)
dry-equalizer (~> 0.3)
dry-inflector (~> 0.1, >= 0.1.2)
dry-logic (~> 1.0, >= 1.0.2)
erubi (1.9.0)
erubis (2.7.0) erubis (2.7.0)
execjs (2.7.0) execjs (2.7.0)
factory_bot (4.8.2) ffi (1.13.1)
activesupport (>= 3.0.0)
factory_bot_rails (4.8.2)
factory_bot (~> 4.8.2)
railties (>= 3.0.0)
ffi (1.9.25)
figaro (1.1.1) figaro (1.1.1)
thor (~> 0.14) thor (~> 0.14)
globalid (0.4.2) globalid (0.4.2)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
grape (1.2.3) grape (1.3.3)
activesupport activesupport
builder builder
dry-types (>= 1.1)
mustermann-grape (~> 1.0.0) mustermann-grape (~> 1.0.0)
rack (>= 1.3.0) rack (>= 1.3.0)
rack-accept rack-accept
virtus (>= 1.0.0)
gyoku (1.3.1) gyoku (1.3.1)
builder (>= 2.1.2) builder (>= 2.1.2)
haml (4.0.7) haml (5.1.2)
temple (>= 0.8.0)
tilt tilt
haml-rails (0.9.0) hashdiff (1.0.1)
actionpack (>= 4.0.1)
activesupport (>= 4.0.1)
haml (>= 4.0.6, < 5.0)
html2haml (>= 1.0.1)
railties (>= 4.0.1)
hashdiff (0.4.0)
hpricot (0.8.6) hpricot (0.8.6)
html2haml (2.1.0) http-accept (1.7.0)
erubis (~> 2.7.0)
haml (~> 4.0)
nokogiri (>= 1.6.0)
ruby_parser (~> 3.5)
http-cookie (1.0.3) http-cookie (1.0.3)
domain_name (~> 0.5) domain_name (~> 0.5)
httpclient (2.8.3) httpclient (2.8.3)
httpi (2.4.4) httpi (2.4.4)
rack rack
socksify socksify
i18n (0.9.5) i18n (1.8.3)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n_data (0.8.0) i18n_data (0.10.0)
ice_nine (0.11.2)
isikukood (0.1.2) isikukood (0.1.2)
iso8601 (0.8.6) iso8601 (0.12.1)
jbuilder (2.2.16) jquery-rails (4.4.0)
activesupport (>= 3.0.0, < 5) rails-dom-testing (>= 1, < 3)
multi_json (~> 1.2)
jquery-rails (4.0.4)
rails-dom-testing (~> 1.0)
railties (>= 4.2.0) railties (>= 4.2.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
jquery-ui-rails (5.0.5) jquery-ui-rails (5.0.5)
railties (>= 3.2.16) railties (>= 3.2.16)
json (1.8.6) json (2.3.1)
kaminari (0.16.3) kaminari (1.2.1)
actionpack (>= 3.0.0) activesupport (>= 4.1.0)
activesupport (>= 3.0.0) kaminari-actionview (= 1.2.1)
libxml-ruby (3.0.0) kaminari-activerecord (= 1.2.1)
loofah (2.2.3) kaminari-core (= 1.2.1)
kaminari-actionview (1.2.1)
actionview
kaminari-core (= 1.2.1)
kaminari-activerecord (1.2.1)
activerecord
kaminari-core (= 1.2.1)
kaminari-core (1.2.1)
libxml-ruby (3.2.0)
listen (3.2.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.4.2)
loofah (2.6.0)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
mail (2.7.1) mail (2.7.1)
mini_mime (>= 0.1.1) mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
method_source (0.8.2) method_source (0.8.2)
mime-types (3.1) mime-types (3.3.1)
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521) mime-types-data (3.2020.0512)
mimemagic (0.3.5)
mina (0.3.1) mina (0.3.1)
open4 (~> 1.3.4) open4 (~> 1.3.4)
rake rake
mini_mime (1.0.1) mini_mime (1.0.2)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
minitest (5.11.3) minitest (5.14.1)
monetize (1.9.0) monetize (1.9.4)
money (~> 6.12) money (~> 6.12)
money (6.12.0) money (6.13.8)
i18n (>= 0.6.4, < 1.1) i18n (>= 0.6.4, <= 2)
money-rails (1.12.0) money-rails (1.13.3)
activesupport (>= 3.0) activesupport (>= 3.0)
monetize (~> 1.9.0) monetize (~> 1.9.0)
money (~> 6.12.0) money (~> 6.13.2)
railties (>= 3.0) railties (>= 3.0)
multi_json (1.13.1) msgpack (1.3.3)
mustermann (1.0.3) multi_json (1.14.1)
mustermann-grape (1.0.0) mustermann (1.1.1)
mustermann (~> 1.0.0) ruby2_keywords (~> 0.0.1)
mustermann-grape (1.0.1)
mustermann (>= 1.0.0)
netrc (0.11.0) netrc (0.11.0)
nokogiri (1.10.3) nio4r (2.5.2)
nokogiri (1.10.10)
mini_portile2 (~> 2.4.0) mini_portile2 (~> 2.4.0)
nori (2.6.0) nori (2.6.0)
open4 (1.3.4) open4 (1.3.4)
orm_adapter (0.5.0) orm_adapter (0.5.0)
paper_trail (4.2.0) paper_trail (10.3.1)
activerecord (>= 3.0, < 6.0) activerecord (>= 4.2)
activesupport (>= 3.0, < 6.0)
request_store (~> 1.1) request_store (~> 1.1)
pdfkit (0.8.4.1) pdfkit (0.8.4.3.1)
pg (0.19.0) pg (1.2.2)
polyamorous (1.3.1) polyamorous (2.3.2)
activerecord (>= 3.0) activerecord (>= 5.2.1)
pry (0.10.1) pry (0.10.1)
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
slop (~> 3.4) slop (~> 3.4)
public_suffix (3.1.0) public_suffix (4.0.5)
puma (3.12.1) puma (4.3.5)
que (0.10.0) nio4r (~> 2.0)
que-web (0.4.0) que (0.14.3)
que-web (0.7.2)
erubis erubis
que (~> 0.8) que (~> 0.8)
sinatra sinatra
rack (1.6.11) rack (2.2.3)
rack-accept (0.4.5) rack-accept (0.4.5)
rack (>= 0.4) rack (>= 0.4)
rack-protection (1.5.5) rack-protection (2.0.8.1)
rack rack
rack-test (0.6.3) rack-test (1.1.0)
rack (>= 1.0) rack (>= 1.0, < 3)
railroady (1.3.0) railroady (1.3.0)
rails (4.2.11.1) rails (6.0.3.2)
actionmailer (= 4.2.11.1) actioncable (= 6.0.3.2)
actionpack (= 4.2.11.1) actionmailbox (= 6.0.3.2)
actionview (= 4.2.11.1) actionmailer (= 6.0.3.2)
activejob (= 4.2.11.1) actionpack (= 6.0.3.2)
activemodel (= 4.2.11.1) actiontext (= 6.0.3.2)
activerecord (= 4.2.11.1) actionview (= 6.0.3.2)
activesupport (= 4.2.11.1) activejob (= 6.0.3.2)
bundler (>= 1.3.0, < 2.0) activemodel (= 6.0.3.2)
railties (= 4.2.11.1) activerecord (= 6.0.3.2)
sprockets-rails activestorage (= 6.0.3.2)
rails-deprecated_sanitizer (1.0.3) activesupport (= 6.0.3.2)
activesupport (>= 4.2.0.alpha) bundler (>= 1.3.0)
rails-dom-testing (1.0.9) railties (= 6.0.3.2)
activesupport (>= 4.2.0, < 5.0) sprockets-rails (>= 2.0.0)
nokogiri (~> 1.6) rails-dom-testing (2.0.3)
rails-deprecated_sanitizer (>= 1.0.1) activesupport (>= 4.2.0)
rails-html-sanitizer (1.0.4) nokogiri (>= 1.6)
loofah (~> 2.2, >= 2.2.2) rails-html-sanitizer (1.3.0)
rails-settings-cached (0.7.2) loofah (~> 2.3)
rails (>= 4.2.0) railties (6.0.3.2)
railties (4.2.11.1) actionpack (= 6.0.3.2)
actionpack (= 4.2.11.1) activesupport (= 6.0.3.2)
activesupport (= 4.2.11.1) method_source
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.20.3, < 2.0)
rake (12.3.2) rake (13.0.1)
ransack (1.5.1) ransack (2.3.2)
actionpack (>= 3.0) activerecord (>= 5.2.1)
activerecord (>= 3.0) activesupport (>= 5.2.1)
activesupport (>= 3.0)
i18n i18n
polyamorous (~> 1.1) polyamorous (= 2.3.2)
rdoc (4.3.0) rb-fsevent (0.10.4)
regexp_parser (1.5.1) rb-inotify (0.10.1)
request_store (1.4.1) ffi (~> 1.0)
rbtree3 (0.6.0)
rdoc (6.2.1)
regexp_parser (1.7.1)
request_store (1.5.0)
rack (>= 1.4) rack (>= 1.4)
responders (2.4.1) responders (3.0.1)
actionpack (>= 4.2.0, < 6.0) actionpack (>= 5.0)
railties (>= 4.2.0, < 6.0) railties (>= 5.0)
rest-client (2.0.1) rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0) http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0) mime-types (>= 1.16, < 4.0)
netrc (~> 0.8) netrc (~> 0.8)
rspec (3.6.0) rspec (3.9.0)
rspec-core (~> 3.6.0) rspec-core (~> 3.9.0)
rspec-expectations (~> 3.6.0) rspec-expectations (~> 3.9.0)
rspec-mocks (~> 3.6.0) rspec-mocks (~> 3.9.0)
rspec-core (3.6.0) rspec-core (3.9.2)
rspec-support (~> 3.6.0) rspec-support (~> 3.9.3)
rspec-expectations (3.6.0) rspec-expectations (3.9.2)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0) rspec-support (~> 3.9.0)
rspec-mocks (3.6.0) rspec-mocks (3.9.1)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0) rspec-support (~> 3.9.0)
rspec-rails (3.6.0) rspec-support (3.9.3)
actionpack (>= 3.0) ruby2_keywords (0.0.2)
activesupport (>= 3.0) rubyzip (2.3.0)
railties (>= 3.0)
rspec-core (~> 3.6.0)
rspec-expectations (~> 3.6.0)
rspec-mocks (~> 3.6.0)
rspec-support (~> 3.6.0)
rspec-support (3.6.0)
ruby_parser (3.8.4)
sexp_processor (~> 4.1)
rubyzip (1.2.2)
safe_yaml (1.0.5) safe_yaml (1.0.5)
sass (3.4.23) sass-rails (6.0.0)
sass-rails (5.0.6) sassc-rails (~> 2.1, >= 2.1.1)
railties (>= 4.0.0, < 6) sassc (2.4.0)
sass (~> 3.1) ffi (~> 1.9)
sprockets (>= 2.8, < 4.0) sassc-rails (2.1.2)
sprockets-rails (>= 2.0, < 4.0) railties (>= 4.0.0)
tilt (>= 1.1, < 3) sassc (>= 2.0)
sassc (2.0.0) sprockets (> 3.0)
ffi (~> 1.9.6) sprockets-rails
rake tilt
savon (2.12.0) savon (2.12.1)
akami (~> 1.2) akami (~> 1.2)
builder (>= 2.1.2) builder (>= 2.1.2)
gyoku (~> 1.2) gyoku (~> 1.2)
@ -380,133 +419,138 @@ GEM
nokogiri (>= 1.8.1) nokogiri (>= 1.8.1)
nori (~> 2.4) nori (~> 2.4)
wasabi (~> 3.4) wasabi (~> 3.4)
sdoc (0.4.1) sdoc (1.1.0)
json (~> 1.7, >= 1.7.7) rdoc (>= 5.0)
rdoc (~> 4.0)
select2-rails (3.5.9.3) select2-rails (3.5.9.3)
thor (~> 0.14) thor (~> 0.14)
selectize-rails (0.12.1) selectize-rails (0.12.1)
selenium-webdriver (3.13.0) selenium-webdriver (3.142.7)
childprocess (~> 0.5) childprocess (>= 0.5, < 4.0)
rubyzip (~> 1.2) rubyzip (>= 1.2.2)
sexp_processor (4.8.0) simplecov (0.17.1)
simplecov (0.16.1)
docile (~> 1.1) docile (~> 1.1)
json (>= 1.8, < 3) json (>= 1.8, < 3)
simplecov-html (~> 0.10.0) simplecov-html (~> 0.10.0)
simplecov-html (0.10.2) simplecov-html (0.10.2)
simpleidn (0.0.7) simpleidn (0.1.1)
sinatra (1.4.8) unf (~> 0.1.4)
rack (~> 1.5) sinatra (2.0.8.1)
rack-protection (~> 1.4) mustermann (~> 1.0)
tilt (>= 1.3, < 3) rack (~> 2.0)
rack-protection (= 2.0.8.1)
tilt (~> 2.0)
sixarm_ruby_unaccent (1.2.0) sixarm_ruby_unaccent (1.2.0)
slop (3.6.0) slop (3.6.0)
socksify (1.7.1) socksify (1.7.1)
sprockets (3.7.2) sprockets (4.0.2)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
sprockets-rails (3.2.1) sprockets-rails (3.2.1)
actionpack (>= 4.0) actionpack (>= 4.0)
activesupport (>= 4.0) activesupport (>= 4.0)
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
temple (0.8.2)
thor (0.20.3) thor (0.20.3)
thread_safe (0.3.6) thread_safe (0.3.6)
tilt (1.4.1) tilt (2.0.10)
tzinfo (1.2.5) truemail (1.8.0)
simpleidn (~> 0.1.1)
tzinfo (1.2.7)
thread_safe (~> 0.1) thread_safe (~> 0.1)
uglifier (4.1.11) uglifier (4.2.0)
execjs (>= 0.3.0, < 3) execjs (>= 0.3.0, < 3)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.2) unf_ext (0.0.7.7)
unicode_utils (1.4.0) unicode_utils (1.4.0)
uniform_notifier (1.9.0)
uuidtools (2.1.5)
validates_email_format_of (1.6.3) validates_email_format_of (1.6.3)
i18n i18n
virtus (1.0.5) warden (1.2.8)
axiom-types (~> 0.1) rack (>= 2.0.6)
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
warden (1.2.7)
rack (>= 1.0)
wasabi (3.5.0) wasabi (3.5.0)
httpi (~> 2.0) httpi (~> 2.0)
nokogiri (>= 1.4.2) nokogiri (>= 1.4.2)
webmock (3.6.0) webdrivers (4.4.1)
nokogiri (~> 1.6)
rubyzip (>= 1.3.0)
selenium-webdriver (>= 3.0, < 4.0)
webmock (3.8.3)
addressable (>= 2.3.6) addressable (>= 2.3.6)
crack (>= 0.3.2) crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0) hashdiff (>= 0.4.0, < 2.0.0)
websocket-driver (0.7.2)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
whenever (0.9.4) whenever (0.9.4)
chronic (>= 0.6.3) chronic (>= 0.6.3)
wkhtmltopdf-binary (0.12.5.4)
xpath (3.2.0) xpath (3.2.0)
nokogiri (~> 1.8) nokogiri (~> 1.8)
zeitwerk (2.3.1)
PLATFORMS PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
active_model-errors_details activerecord-import
activerecord-import (= 0.7.0)
airbrake airbrake
autodoc autodoc
bootsnap (>= 1.1.0)
bootstrap-sass (~> 3.4) bootstrap-sass (~> 3.4)
bullet (= 4.14.7) cancancan
cancancan (= 1.11.0)
capybara capybara
coderay (= 1.1.0) coderay (= 1.1.0)
coffee-rails (= 4.1.0) coffee-rails (>= 5.0)
company_register! company_register!
countries countries
daemons-rails (= 1.2.1) daemons-rails (= 1.2.1)
data_migrate! data_migrate (~> 6.1)
database_cleaner database_cleaner
devise (~> 4.0) devise (~> 4.7)
digidoc_client! digidoc_client!
directo!
domain_name
e_invoice! e_invoice!
epp (= 1.5.0)! epp!
epp-xml (= 1.1.0)! epp-xml (= 1.1.0)!
factory_bot_rails
figaro (= 1.1.1) figaro (= 1.1.1)
grape grape
haml-rails (= 0.9.0) haml (~> 5.0)
html2haml (= 2.1.0)
isikukood isikukood
iso8601 (= 0.8.6) iso8601 (= 0.12.1)
jbuilder (= 2.2.16) jquery-rails
jquery-rails (= 4.0.4)
jquery-ui-rails (= 5.0.5) jquery-ui-rails (= 5.0.5)
kaminari (= 0.16.3) kaminari
lhv!
listen (= 3.2.1)
mina (= 0.3.1) mina (= 0.3.1)
minitest (~> 5.14)
money-rails money-rails
nokogiri nokogiri
paper_trail (~> 4.0) paper_trail (~> 10.3)
pdfkit pdfkit
pg (= 0.19.0) pg (= 1.2.2)
pry (= 0.10.1) pry (= 0.10.1)
puma puma
que (= 0.10.0) que
que-web (= 0.4.0) que-web
railroady (= 1.3.0) railroady (= 1.3.0)
rails (= 4.2.11.1) rails (~> 6.0)
rails-settings-cached (= 0.7.2) ransack (~> 2.3)
ransack (= 1.5.1)
rest-client rest-client
rspec-rails (~> 3.6) sass-rails
sass-rails (= 5.0.6) sdoc (~> 1.1)
sdoc (= 0.4.1)
select2-rails (= 3.5.9.3) select2-rails (= 3.5.9.3)
selectize-rails (= 0.12.1) selectize-rails (= 0.12.1)
selenium-webdriver simplecov (= 0.17.1)
simplecov simpleidn (= 0.1.1)
simpleidn (= 0.0.7) truemail (~> 1.7)
uglifier uglifier
uuidtools (= 2.1.5)
validates_email_format_of (= 1.6.3) validates_email_format_of (= 1.6.3)
webdrivers
webmock webmock
whenever (= 0.9.4) whenever (= 0.9.4)
wkhtmltopdf-binary (~> 0.12.5.1)
BUNDLED WITH BUNDLED WITH
1.17.3 2.1.4

View file

@ -1,8 +1,8 @@
Domain Registry Domain Registry
=============== ===============
[![Build Status](https://travis-ci.org/internetee/registry.svg?branch=master)](https://travis-ci.org/internetee/registry) [![Build Status](https://travis-ci.org/internetee/registry.svg?branch=master)](https://travis-ci.org/internetee/registry)
[![Code Climate](https://codeclimate.com/github/internetee/registry/badges/gpa.svg)](https://codeclimate.com/github/internetee/registry) [![Maintainability](https://api.codeclimate.com/v1/badges/a91e4ae502a6c5245160/maintainability)](https://codeclimate.com/github/internetee/registry/maintainability)
[![Test Coverage](https://codeclimate.com/github/internetee/registry/badges/coverage.svg)](https://codeclimate.com/github/internetee/registry/coverage) [![Test Coverage](https://api.codeclimate.com/v1/badges/a91e4ae502a6c5245160/test_coverage)](https://codeclimate.com/github/internetee/registry/test_coverage)
[![Documentation Status](https://readthedocs.org/projects/eeregistry/badge/?version=latest)](http://docs.internet.ee/en/latest/?badge=latest) [![Documentation Status](https://readthedocs.org/projects/eeregistry/badge/?version=latest)](http://docs.internet.ee/en/latest/?badge=latest)
Full stack top-level domain (TLD) management. Full stack top-level domain (TLD) management.
@ -17,15 +17,15 @@ Documentation
------------- -------------
* [EPP documentation](/doc/epp) * [EPP documentation](/doc/epp)
* [EPP request-response examples](/doc/epp-examples.md) * [EPP request-response examples](/doc/epp_examples.md)
* [REPP documentation](/doc/repp-doc.md) * [REPP documentation](/doc/repp_doc.md)
* [Database diagram](/doc/models_complete.svg) * [Database diagram](/doc/models_complete.svg)
* [Controllers diagram](/doc/controllers_complete.svg) * [Controllers diagram](/doc/controllers_complete.svg)
### Updating documentation ### Updating documentation
AUTODOC=true rspec spec/requests AUTODOC=true rspec spec/requests
EPP_DOC=true rspec spec/epp --tag epp --require support/epp_doc.rb --format EppDoc > doc/epp-examples.md EPP_DOC=true rspec spec/epp --tag epp --require support/epp_doc.rb --format EppDoc > doc/epp_examples.md
Installation Installation
------------ ------------
@ -41,8 +41,8 @@ Manual demo install and database setup:
cd demo-registry cd demo-registry
rbenv local 2.2.2 rbenv local 2.2.2
bundle bundle
cp config/application-example.yml config/application.yml # and edit it cp config/application.yml.sample config/application.yml # and edit it
cp config/database-example.yml config/database.yml # and edit it cp config/database.yml.sample config/database.yml # and edit it
bundle exec rake db:setup:all # for production, please follow deployment howto bundle exec rake db:setup:all # for production, please follow deployment howto
bundle exec rake bootstrap bundle exec rake bootstrap
bundle exec rake assets:precompile bundle exec rake assets:precompile

View file

@ -1,6 +1,6 @@
# Add your own tasks in files placed in lib/tasks ending in .rake, # Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__) require_relative 'config/application'
Rails.application.load_tasks Rails.application.load_tasks

View file

@ -30,7 +30,8 @@ module Repp
webclient_cert_name = ENV['webclient_cert_common_name'] || 'webclient' webclient_cert_name = ENV['webclient_cert_common_name'] || 'webclient'
error! "Webclient #{message} #{webclient_cert_name}", 401 if webclient_cert_name != request_name error! "Webclient #{message} #{webclient_cert_name}", 401 if webclient_cert_name != request_name
else else
unless @current_user.api_pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'], request.env['HTTP_SSL_CLIENT_S_DN_CN']) unless @current_user.pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'],
request.env['HTTP_SSL_CLIENT_S_DN_CN'])
error! "#{message} #{@current_user.username}", 401 error! "#{message} #{@current_user.username}", 401
end end
end end

View file

@ -0,0 +1,3 @@
//= link_tree ../images
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css

View file

@ -47,12 +47,6 @@ class @Autocomplete
selector: '.js-contact-typeahead' selector: '.js-contact-typeahead'
hiddenSelector: '.js-contact-id' hiddenSelector: '.js-contact-id'
@bindAdminRegistrarSearch: ->
Autocomplete.bindTypeahead
remote: '/admin/registrars/search'
selector: '.js-registrar-typeahead'
hiddenSelector: '.js-registrar-id'
@bindClientContactSearch: -> @bindClientContactSearch: ->
Autocomplete.bindTypeahead Autocomplete.bindTypeahead
remote: '/client/contacts/search' remote: '/client/contacts/search'

View file

@ -133,12 +133,6 @@ body.login
padding-top: 40px padding-top: 40px
padding-bottom: 40px padding-bottom: 40px
.form-signin
.form-signin-heading,
.form-signin
.checkbox
margin-bottom: 10px
.form-signin .form-signin
max-width: 330px max-width: 330px
padding: 15px padding: 15px

View file

@ -15,6 +15,9 @@ body > .container
padding-top: 15px padding-top: 15px
font-size: 10px font-size: 10px
a.footer-version-link
color: black
.nowrap .nowrap
white-space: nowrap white-space: nowrap

View file

@ -23,11 +23,11 @@ module Admin
@q.sorts = 'id desc' if @q.sorts.empty? @q.sorts = 'id desc' if @q.sorts.empty?
@account_activities = @q.result.page(params[:page]).per(params[:results_per_page]) @account_activities = @q.result.page(params[:page]).per(params[:results_per_page])
sort = @account_activities.orders.map(&:to_sql).join(",")
# can do here inline SQL as it's our
if params[:page] && params[:page].to_i > 1 if params[:page] && params[:page].to_i > 1
@sum = @q.result.reorder(sort).limit(@account_activities.offset_value).sum(:sum) + @b.result.where("account_activities.id NOT IN (#{@q.result.select(:id).to_sql})").sum(:sum) @sum = @q.result.limit(@account_activities.offset_value).sum(:sum) +
@b.result.where("account_activities.id NOT IN (#{@q.result.select(:id).to_sql})")
.sum(:sum)
else else
@sum = @b.result.where("account_activities.id NOT IN (#{@q.result.select(:id).to_sql})").sum(:sum) @sum = @b.result.where("account_activities.id NOT IN (#{@q.result.select(:id).to_sql})").sum(:sum)
end end

View file

@ -1,7 +1,6 @@
module Admin module Admin
class ApiUsersController < BaseController class ApiUsersController < BaseController
load_and_authorize_resource load_and_authorize_resource
before_action :set_api_user, only: [:show, :edit, :update, :destroy]
def index def index
@q = ApiUser.includes(:registrar).search(params[:q]) @q = ApiUser.includes(:registrar).search(params[:q])
@ -9,18 +8,17 @@ module Admin
end end
def new def new
@registrar = Registrar.find_by(id: params[:registrar_id]) @api_user = registrar.api_users.build
@api_user = ApiUser.new(registrar: @registrar)
end end
def create def create
@api_user = ApiUser.new(api_user_params) @api_user = registrar.api_users.build(api_user_params)
if @api_user.save if @api_user.valid?
flash[:notice] = I18n.t('record_created') @api_user.save!
redirect_to [:admin, @api_user] redirect_to admin_registrar_api_user_path(@api_user.registrar, @api_user),
notice: t('.created')
else else
flash.now[:alert] = I18n.t('failed_to_create_record')
render 'new' render 'new'
end end
end end
@ -32,39 +30,31 @@ module Admin
end end
def update def update
if params[:api_user][:plain_text_password].blank? @api_user.attributes = api_user_params
params[:api_user].delete(:plain_text_password)
end
if @api_user.update(api_user_params) if @api_user.valid?
flash[:notice] = I18n.t('record_updated') @api_user.save!
redirect_to [:admin, @api_user] redirect_to admin_registrar_api_user_path(@api_user.registrar, @api_user),
notice: t('.updated')
else else
flash.now[:alert] = I18n.t('failed_to_update_record')
render 'edit' render 'edit'
end end
end end
def destroy def destroy
if @api_user.destroy @api_user.destroy!
flash[:notice] = I18n.t('record_deleted') redirect_to admin_registrar_path(@api_user.registrar), notice: t('.deleted')
redirect_to admin_api_users_path
else
flash.now[:alert] = I18n.t('failed_to_delete_record')
render 'show'
end
end end
private private
def set_api_user
@api_user = ApiUser.find(params[:id])
end
def api_user_params def api_user_params
params.require(:api_user).permit(:username, :plain_text_password, :active, params.require(:api_user).permit(:username, :plain_text_password, :active,
:registrar_id, :registrar_typeahead,
:identity_code, { roles: [] }) :identity_code, { roles: [] })
end end
def registrar
Registrar.find(params[:registrar_id])
end
end end
end end

View file

@ -60,7 +60,7 @@ module Admin
end end
def bind_invoices def bind_invoices
@bank_statement.bind_invoices @bank_statement.bind_invoices(manual: true)
flash[:notice] = t('invoices_were_fully_binded') if @bank_statement.fully_binded? flash[:notice] = t('invoices_were_fully_binded') if @bank_statement.fully_binded?
flash[:warning] = t('invoices_were_partially_binded') if @bank_statement.partially_binded? flash[:warning] = t('invoices_were_partially_binded') if @bank_statement.partially_binded?

View file

@ -34,7 +34,7 @@ module Admin
end end
def bind def bind
if @bank_transaction.bind_invoice(params[:invoice_no]) if @bank_transaction.bind_invoice(params[:invoice_no], manual: true)
flash[:notice] = I18n.t('record_created') flash[:notice] = I18n.t('record_created')
redirect_to [:admin, @bank_transaction] redirect_to [:admin, @bank_transaction]
else else

View file

@ -2,6 +2,7 @@ module Admin
class BaseController < ApplicationController class BaseController < ApplicationController
before_action :authenticate_admin_user! before_action :authenticate_admin_user!
helper_method :head_title_sufix helper_method :head_title_sufix
before_action :set_paper_trail_whodunnit
def head_title_sufix def head_title_sufix
t(:admin_head_title_sufix) t(:admin_head_title_sufix)

View file

@ -34,7 +34,7 @@ module Admin
if @certificate.destroy if @certificate.destroy
flash[:notice] = I18n.t('record_deleted') flash[:notice] = I18n.t('record_deleted')
redirect_to admin_api_user_path(@api_user) redirect_to admin_registrar_api_user_path(@api_user.registrar, @api_user)
else else
flash.now[:alert] = I18n.t('failed_to_delete_record') flash.now[:alert] = I18n.t('failed_to_delete_record')
render 'show' render 'show'

View file

@ -3,6 +3,7 @@ module Admin
load_and_authorize_resource load_and_authorize_resource
before_action :set_contact, only: [:show] before_action :set_contact, only: [:show]
helper_method :ident_types helper_method :ident_types
helper_method :domain_filter_params
def index def index
params[:q] ||= {} params[:q] ||= {}
@ -12,19 +13,27 @@ module Admin
search_params[:registrant_domains_id_not_null] = 1 search_params[:registrant_domains_id_not_null] = 1
end end
contacts = Contact.includes(:registrar).joins(:registrar).select('contacts.*, registrars.name') contacts = Contact.includes(:registrar).joins(:registrar)
.select('contacts.*, registrars.name')
contacts = contacts.filter_by_states(params[:statuses_contains].join(',')) if params[:statuses_contains] contacts = contacts.filter_by_states(params[:statuses_contains].join(',')) if params[:statuses_contains]
contacts = contacts.where("ident_country_code is null or ident_country_code=''") if params[:only_no_country_code].eql?('1') contacts = filter_by_flags(contacts)
normalize_search_parameters do normalize_search_parameters do
@q = contacts.search(search_params) @q = contacts.search(search_params)
@contacts = @q.result.uniq.page(params[:page]) @contacts = @q.result.distinct.page(params[:page])
end end
@contacts = @contacts.per(params[:results_per_page]) if params[:results_per_page].to_i.positive? @contacts = @contacts.per(params[:results_per_page]) if params[:results_per_page].to_i.positive?
end end
def filter_by_flags(contacts)
if params[:only_no_country_code].eql?('1')
contacts = contacts.where("ident_country_code is null or ident_country_code=''")
end
contacts = contacts.email_verification_failed if params[:email_verification_failed].eql?('1')
contacts
end
def search def search
render json: Contact.search_by_query(params[:q]) render json: Contact.search_by_query(params[:q])
end end
@ -84,5 +93,9 @@ module Admin
def ident_types def ident_types
Contact::Ident.types Contact::Ident.types
end end
def domain_filter_params
params.permit(:domain_filter)
end
end end
end end

View file

@ -0,0 +1,74 @@
# frozen_string_literal: true
module Admin
class DisputesController < BaseController
load_and_authorize_resource
before_action :set_dispute, only: %i[show edit update delete]
# GET /admin/disputes
def index
params[:q] ||= {}
@disputes = sortable_dispute_query_for(Dispute.active.all, params[:q])
@closed_disputes = sortable_dispute_query_for(Dispute.closed.all, params[:q], closed: true)
end
# GET /admin/disputes/1
def show; end
# GET /admin/disputes/new
def new
@dispute = Dispute.new
end
# GET /admin/disputes/1/edit
def edit; end
# POST /admin/disputes
def create
@dispute = Dispute.new(dispute_params)
if @dispute.save
notice = 'Dispute was successfully created'
notice += @dispute.domain ? '.' : ' for domain that is not registered.'
redirect_to admin_disputes_url, notice: notice
else
render :new
end
end
# PATCH/PUT /admin/disputes/1
def update
if @dispute.update(dispute_params.except(:domain_name))
redirect_to admin_disputes_url, notice: 'Dispute was successfully updated.'
else
render :edit
end
end
# DELETE /admin/disputes/1
def delete
@dispute.close(initiator: 'Admin')
redirect_to admin_disputes_url, notice: 'Dispute was successfully closed.'
end
private
def sortable_dispute_query_for(disputes, query, closed: false)
@q = disputes.order(:domain_name).search(query)
disputes = @q.result.page(closed ? params[:closed_page] : params[:page])
return disputes.per(params[:results_per_page]) if params[:results_per_page].present?
disputes
end
# Use callbacks to share common setup or constraints between actions.
def set_dispute
@dispute = Dispute.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def dispute_params
params.require(:dispute).permit(:domain_name, :password, :starts_at, :comment)
end
end
end

View file

@ -5,21 +5,27 @@ module Admin
authorize! :manage, domain authorize! :manage, domain
domain.transaction do domain.transaction do
domain.schedule_force_delete domain.schedule_force_delete(type: force_delete_type)
domain.registrar.notifications.create!(text: t('force_delete_set_on_domain', domain.registrar.notifications.create!(text: t('force_delete_set_on_domain',
domain_name: domain.name)) domain_name: domain.name,
outzone_date: domain.outzone_date,
purge_date: domain.purge_date))
if notify_by_email? notify_by_email if notify_by_email?
DomainDeleteMailer.forced(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant,
template_name: params[:template_name]).deliver_now
end
end end
redirect_to edit_admin_domain_url(domain), notice: t('.scheduled') redirect_to edit_admin_domain_url(domain), notice: t('.scheduled')
end end
def notify_by_email
if force_delete_type == :fast_track
send_email
domain.update(contact_notification_sent_date: Time.zone.today)
else
domain.update(template_name: params[:template_name])
end
end
def destroy def destroy
authorize! :manage, domain authorize! :manage, domain
domain.cancel_force_delete domain.cancel_force_delete
@ -33,7 +39,22 @@ module Admin
end end
def notify_by_email? def notify_by_email?
ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:notify_by_email]) ActiveRecord::Type::Boolean.new.cast(params[:notify_by_email])
end
def send_email
DomainDeleteMailer.forced(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant,
template_name: params[:template_name]).deliver_now
end
def force_delete_type
soft_delete? ? :soft : :fast_track
end
def soft_delete?
ActiveRecord::Type::Boolean.new.cast(params[:soft_delete])
end end
end end
end end

View file

@ -1,13 +0,0 @@
module Admin
class KeyrelaysController < BaseController
load_and_authorize_resource
def index
@q = Keyrelay.includes(:requester, :accepter).search(params[:q])
@keyrelays = @q.result.page(params[:page])
end
def show;
end
end
end

View file

@ -5,7 +5,11 @@ module Admin
def show def show
@ld = LegalDocument.find(params[:id]) @ld = LegalDocument.find(params[:id])
filename = @ld.path.split('/').last filename = @ld.path.split('/').last
send_data File.open(@ld.path).read, filename: filename file = File.open(@ld.path)&.read
send_data file, filename: filename
rescue Errno::ENOENT
flash[:notice] = I18n.t('legal_doc_not_found')
redirect_to [:admin, @ld.documentable]
end end
end end
end end

View file

@ -29,7 +29,6 @@ module Admin
# steal token # steal token
token = @domain.registrant_verification_token token = @domain.registrant_verification_token
@registrant_verification = RegistrantVerification.new(domain_id: @domain.id, @registrant_verification = RegistrantVerification.new(domain_id: @domain.id,
domain_name: @domain.name,
verification_token: token) verification_token: token)
end end

View file

@ -26,7 +26,6 @@ module Admin
# steal token # steal token
token = @domain.registrant_verification_token token = @domain.registrant_verification_token
@registrant_verification = RegistrantVerification.new(domain_id: @domain.id, @registrant_verification = RegistrantVerification.new(domain_id: @domain.id,
domain_name: @domain.name,
verification_token: token) verification_token: token)
end end

View file

@ -74,6 +74,8 @@ module Admin
:vat_rate, :vat_rate,
:accounting_customer_code, :accounting_customer_code,
:billing_email, :billing_email,
:legaldoc_optout,
:legaldoc_optout_comment,
:iban, :iban,
:language) :language)
end end

View file

@ -3,21 +3,23 @@ module Admin
load_and_authorize_resource load_and_authorize_resource
def index def index
@settings = Setting.unscoped @settings = SettingEntry.unscoped
@validation_settings = SettingEntry.with_group('domain_validation')
@expiration_settings = SettingEntry.with_group('domain_expiration')
@other_settings = SettingEntry.with_group('other')
.where.not(code: 'default_language')
@billing_settings = SettingEntry.with_group('billing')
@contacts_settings = SettingEntry.with_group('contacts')
end end
def create def create
@errors = Setting.params_errors(casted_settings) update = SettingEntry.update(casted_settings.keys, casted_settings.values)
if @errors.empty? if update
casted_settings.each do |k, v|
Setting[k] = v
end
flash[:notice] = t('.saved') flash[:notice] = t('.saved')
redirect_to [:admin, :settings] redirect_to %i[admin settings]
else else
flash[:alert] = @errors.values.uniq.join(", ") flash[:alert] = update.errors.values.uniq.join(', ')
render "admin/settings/index" render 'admin/settings/index'
end end
end end
@ -27,10 +29,7 @@ module Admin
settings = {} settings = {}
params[:settings].each do |k, v| params[:settings].each do |k, v|
settings[k] = v settings[k] = { value: v }
settings[k] = v.to_i if Setting.integer_settings.include?(k.to_sym)
settings[k] = v.to_f if Setting.float_settings.include?(k.to_sym)
settings[k] = (v == 'true' ? true : false) if Setting.boolean_settings.include?(k.to_sym)
end end
settings settings

View file

@ -13,7 +13,7 @@ module Admin
send_data @zonefile, filename: "#{params[:origin]}.txt" send_data @zonefile, filename: "#{params[:origin]}.txt"
else else
flash[:alert] = 'Origin not supported' flash[:alert] = 'Origin not supported'
redirect_to :back redirect_back(fallback_location: root_path)
end end
end end
end end

View file

@ -5,7 +5,7 @@ module Api
def cors_preflight_check def cors_preflight_check
set_access_control_headers set_access_control_headers
render text: '' render plain: ''
end end
def set_access_control_headers def set_access_control_headers

View file

@ -30,6 +30,8 @@ module Api
raise "Invalid status #{params[:status]}" raise "Invalid status #{params[:status]}"
end end
auction.mark_deadline(params[:registration_deadline]) if params[:registration_deadline]
if auction.payment_not_received? || auction.domain_not_registered? if auction.payment_not_received? || auction.domain_not_registered?
update_whois_from_auction(Auction.pending(auction.domain)) update_whois_from_auction(Auction.pending(auction.domain))
else else

View file

@ -1,8 +1,8 @@
require 'rails5_api_controller_backport'
module Api module Api
module V1 module V1
class BaseController < ActionController::API class BaseController < ActionController::API
rescue_from ActiveRecord::RecordNotFound, with: :not_found_error
private private
def authenticate def authenticate
@ -10,6 +10,12 @@ module Api
head :unauthorized unless ip_allowed head :unauthorized unless ip_allowed
end end
def not_found_error
uuid = params['uuid']
json = { error: 'Not Found', uuid: uuid, message: 'Record not found' }
render json: json, status: :not_found
end
def allowed_ips def allowed_ips
ENV['auction_api_allowed_ips'].split(',').map(&:strip) ENV['auction_api_allowed_ips'].split(',').map(&:strip)
end end

View file

@ -1,4 +1,3 @@
require 'rails5_api_controller_backport'
require 'auth_token/auth_token_creator' require 'auth_token/auth_token_creator'
module Api module Api
@ -16,7 +15,7 @@ module Api
end end
def eid def eid
user = RegistrantUser.find_or_create_by_api_data(eid_params) user = RegistrantUser.find_or_create_by_api_data(eid_params.to_h)
token = create_token(user) token = create_token(user)
if token if token

View file

@ -1,4 +1,3 @@
require 'rails5_api_controller_backport'
require 'auth_token/auth_token_decryptor' require 'auth_token/auth_token_decryptor'
module Api module Api
@ -45,7 +44,7 @@ module Api
# This controller does not inherit from ApplicationController, # This controller does not inherit from ApplicationController,
# so user_for_paper_trail method is not usable. # so user_for_paper_trail method is not usable.
def set_paper_trail_whodunnit def set_paper_trail_whodunnit
::PaperTrail.whodunnit = current_registrant_user.id_role_username ::PaperTrail.request.whodunnit = current_registrant_user.id_role_username
end end
def show_not_found_error def show_not_found_error

View file

@ -1,9 +1,10 @@
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
check_authorization unless: :devise_controller? check_authorization unless: :devise_controller?
before_action :set_paper_trail_whodunnit
# Prevent CSRF attacks by raising an exception. # Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead. # For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception protect_from_forgery with: :exception, prepend: true
before_action do before_action do
resource = controller_name.singularize.to_sym resource = controller_name.singularize.to_sym

View file

@ -0,0 +1,406 @@
module Epp
class BaseController < ActionController::Base
class AuthorizationError < StandardError; end
skip_before_action :verify_authenticity_token
check_authorization
layout false
before_action :ensure_session_id_passed
before_action :generate_svtrid
before_action :latin_only
before_action :validate_against_schema
before_action :validate_request
before_action :update_epp_session, if: -> { signed_in? }
around_action :wrap_exceptions
helper_method :current_user
helper_method :resource
rescue_from StandardError, with: :respond_with_command_failed_error
rescue_from AuthorizationError, with: :respond_with_authorization_error
rescue_from ActiveRecord::RecordNotFound, with: :respond_with_object_does_not_exist_error
before_action :set_paper_trail_whodunnit
protected
def respond_with_command_failed_error(exception)
epp_errors << {
code: '2400',
msg: 'Command failed',
}
handle_errors
log_exception(exception)
end
def respond_with_object_does_not_exist_error
epp_errors << {
code: '2303',
msg: 'Object does not exist',
}
handle_errors
end
def respond_with_authorization_error
epp_errors << {
code: '2201',
msg: 'Authorization error',
}
handle_errors
end
private
def wrap_exceptions
yield
rescue CanCan::AccessDenied
raise AuthorizationError
end
def validate_against_schema
return if %w[hello error].include?(params[:action])
schema.validate(params[:nokogiri_frame]).each do |error|
epp_errors << {
code: 2001,
msg: error
}
end
handle_errors and return if epp_errors.any?
end
def schema
EPP_ALL_SCHEMA
end
def generate_svtrid
@svTRID = "ccReg-#{format('%010d', rand(10 ** 10))}"
end
def params_hash # TODO: THIS IS DEPRECATED AND WILL BE REMOVED IN FUTURE
@params_hash ||= Hash.from_xml(params[:frame]).with_indifferent_access
end
def epp_session
EppSession.find_by(session_id: epp_session_id)
end
def current_user
return unless signed_in?
epp_session.user
end
# ERROR + RESPONSE HANDLING
def epp_errors
@errors ||= []
end
def handle_errors(obj = nil)
@errors ||= []
if obj
obj.construct_epp_errors
@errors += obj.errors[:epp_errors]
end
if params[:parsed_frame].at_css('update')
@errors.each_with_index do |errors, index|
if errors[:code] == '2304' &&
errors[:value].present? &&
errors[:value][:val] == DomainStatus::SERVER_DELETE_PROHIBITED &&
errors[:value][:obj] == 'status'
@errors[index][:value][:val] = DomainStatus::PENDING_UPDATE
end
end
end
@errors.uniq!
render_epp_response '/epp/error'
end
def render_epp_response(*args)
@response = render_to_string(*args, formats: [:xml])
render xml: @response
write_to_epp_log
end
# VALIDATION
def latin_only
return true if params['frame'].blank?
if params['frame'].match?(/\A[\p{Latin}\p{Z}\p{P}\p{S}\p{Cc}\p{Cf}\w_\'\+\-\.\(\)\/]*\Z/i)
return true
end
epp_errors << {
msg: 'Parameter value policy error. Allowed only Latin characters.',
code: '2306'
}
handle_errors and return false
end
# VALIDATION
def validate_request
validation_method = "validate_#{params[:action]}"
return unless respond_to?(validation_method, true)
send(validation_method)
# validate legal document's type here because it may be in most of the requests
@prefix = nil
if element_count('extdata > legalDocument').positive?
requires_attribute('extdata > legalDocument', 'type', values: LegalDocument::TYPES, policy: true)
end
handle_errors and return if epp_errors.any?
end
# let's follow grape's validations: https://github.com/intridea/grape/#parameter-validation-and-coercion
# Adds error to epp_errors if element is missing or blank
# Returns last element of selectors if it exists
#
# requires 'transfer'
#
# TODO: Add possibility to pass validations / options in the method
def requires(*selectors)
options = selectors.extract_options!
allow_blank = options[:allow_blank] ||= false # allow_blank is false by default
el, missing = nil, nil
selectors.each do |selector|
full_selector = [@prefix, selector].compact.join(' ')
attr = selector.split('>').last.strip.underscore
el = params[:parsed_frame].css(full_selector).first
if allow_blank
missing = el.nil?
else
missing = el.present? ? el.text.blank? : true
end
epp_errors << {
code: '2003',
msg: I18n.t('errors.messages.required_parameter_missing', key: "#{full_selector} [#{attr}]")
} if missing
end
missing ? false : el # return last selector if it was present
end
# Adds error to epp_errors if element or attribute is missing or attribute attribute is not one
# of the values
#
# requires_attribute 'transfer', 'op', values: %(approve, query, reject)
def requires_attribute(element_selector, attribute_selector, options)
element = requires(element_selector, allow_blank: options[:allow_blank])
return unless element
attribute = element[attribute_selector]
unless attribute
epp_errors << {
code: '2003',
msg: I18n.t('errors.messages.required_parameter_missing', key: attribute_selector)
}
return
end
return if options[:values].include?(attribute)
if options[:policy]
epp_errors << {
code: '2306',
msg: I18n.t('attribute_is_invalid', attribute: attribute_selector)
}
else
epp_errors << {
code: '2004',
msg: I18n.t('parameter_value_range_error', key: attribute_selector)
}
end
end
def optional_attribute(element_selector, attribute_selector, options)
full_selector = [@prefix, element_selector].compact.join(' ')
element = params[:parsed_frame].css(full_selector).first
return unless element
attribute = element[attribute_selector]
return if (attribute && options[:values].include?(attribute)) || !attribute
epp_errors << {
code: '2306',
msg: I18n.t('attribute_is_invalid', attribute: attribute_selector)
}
end
def exactly_one_of(*selectors)
full_selectors = create_full_selectors(*selectors)
return if element_count(*full_selectors, use_prefix: false) == 1
epp_errors << {
code: '2306',
msg: I18n.t(:exactly_one_parameter_required, params: full_selectors.join(' OR '))
}
end
def mutually_exclusive(*selectors)
full_selectors = create_full_selectors(*selectors)
return if element_count(*full_selectors, use_prefix: false) <= 1
epp_errors << {
code: '2306',
msg: I18n.t(:mutally_exclusive_params, params: full_selectors.join(', '))
}
end
def optional(selector, *validations)
full_selector = [@prefix, selector].compact.join(' ')
el = params[:parsed_frame].css(full_selector).first
return unless el&.text.present?
value = el.text
validations.each do |x|
validator = "#{x.first[0]}_validator".camelize.constantize
err = validator.validate_epp(selector.split(' ').last, value)
epp_errors << err if err
end
end
# Returns how many elements were present in the request
# if use_prefix is true, @prefix will be prepended to selectors e.g create > create > name
# default is true
#
# @prefix = 'create > create >'
# element_count 'name', 'registrar', use_prefix: false
# => 2
def element_count(*selectors)
options = selectors.extract_options!
use_prefix = options[:use_prefix] != false # use_prefix is true by default
present_count = 0
selectors.each do |selector|
full_selector = use_prefix ? [@prefix, selector].compact.join(' ') : selector
el = params[:parsed_frame].css(full_selector).first
present_count += 1 if el && el.text.present?
end
present_count
end
def create_full_selectors(*selectors)
selectors.map { |x| [@prefix, x].compact.join(' ') }
end
def xml_attrs_present?(ph, attributes) # TODO: THIS IS DEPRECATED AND WILL BE REMOVED IN FUTURE
attributes.each do |x|
epp_errors << {
code: '2003',
msg: I18n.t('errors.messages.required_parameter_missing', key: x.last)
} unless has_attribute(ph, x)
end
epp_errors.empty?
end
def has_attribute(ph, path) # TODO: THIS IS DEPRECATED AND WILL BE REMOVED IN FUTURE
path.reduce(ph) do |location, key|
location.respond_to?(:keys) ? location[key] : nil
end
end
def write_to_epp_log
request_command = params[:command] || params[:action] # error receives :command, other methods receive :action
frame = params[:raw_frame] || params[:frame]
# filter pw
if request_command == 'login' && frame.present?
frame.gsub!(/pw>.+<\//, 'pw>[FILTERED]</')
end
trimmed_request = frame.gsub(/<eis:legalDocument([^>]+)>([^<])+<\/eis:legalDocument>/, "<eis:legalDocument>[FILTERED]</eis:legalDocument>") if frame.present?
ApiLog::EppLog.create({
request: trimmed_request,
request_command: request_command,
request_successful: epp_errors.empty?,
request_object: resource ? "#{params[:epp_object_type]}: #{resource.class} - #{resource.id} - #{resource.name}" : params[:epp_object_type],
response: @response,
api_user_name: @api_user.try(:username) || current_user.try(:username) || 'api-public',
api_user_registrar: @api_user.try(:registrar).try(:to_s) || current_user.try(:registrar).try(:to_s),
ip: request.ip,
uuid: request.uuid
})
end
def resource
name = self.class.to_s.sub("Epp::", "").sub("Controller", "").underscore.singularize
instance_variable_get("@#{name}")
end
def signed_in?
epp_session
end
def epp_session_id
cookies[:session] # Passed by mod_epp https://github.com/mod-epp/mod-epp#requestscript-interface
end
def ensure_session_id_passed
raise 'EPP session id is empty' unless epp_session_id.present?
end
def update_epp_session
iptables_counter_update
if session_timeout_reached?
@api_user = current_user # cache current_user for logging
epp_session.destroy
epp_errors << {
msg: t('session_timeout'),
code: '2201'
}
handle_errors and return
else
epp_session.update_column(:updated_at, Time.zone.now)
end
end
def session_timeout_reached?
timeout = 5.minutes
epp_session.updated_at < (Time.zone.now - timeout)
end
def iptables_counter_update
return if ENV['iptables_counter_enabled'].blank? && ENV['iptables_counter_enabled'] != 'true'
return if current_user.blank?
counter_update(current_user.registrar_code, ENV['iptables_server_ip'])
end
def counter_update(registrar_code, ip)
counter_proc = "/proc/net/xt_recent/#{registrar_code}"
begin
File.open(counter_proc, 'a') do |f|
f.puts "+#{ip}"
end
rescue Errno::ENOENT => e
logger.error "IPTABLES COUNTER UPDATE: cannot open #{counter_proc}: #{e}"
rescue Errno::EACCES => e
logger.error "IPTABLES COUNTER UPDATE: no permission #{counter_proc}: #{e}"
rescue IOError => e
logger.error "IPTABLES COUNTER UPDATE: cannot write #{ip} to #{counter_proc}: #{e}"
end
end
def log_exception(exception)
logger.error(([exception.message] + exception.backtrace).join($INPUT_RECORD_SEPARATOR))
notify_airbrake(exception)
end
def user_for_paper_trail
current_user ? current_user.id_role_username : 'anonymous'
end
end
end

View file

@ -1,210 +1,214 @@
class Epp::ContactsController < EppController require 'deserializers/xml/contact_update'
before_action :find_contact, only: [:info, :update, :delete]
before_action :find_password, only: [:info, :update, :delete]
helper_method :address_processing?
def info module Epp
authorize! :info, @contact, @password class ContactsController < BaseController
render_epp_response 'epp/contacts/info' before_action :find_contact, only: [:info, :update, :delete]
end before_action :find_password, only: [:info, :update, :delete]
helper_method :address_processing?
def check def info
authorize! :check, Epp::Contact authorize! :info, @contact, @password
render_epp_response 'epp/contacts/info'
end
ids = params[:parsed_frame].css('id').map(&:text) def check
@results = Epp::Contact.check_availability(ids) authorize! :check, Epp::Contact
render_epp_response '/epp/contacts/check'
end
def create ids = params[:parsed_frame].css('id').map(&:text)
authorize! :create, Epp::Contact @results = Epp::Contact.check_availability(ids)
frame = params[:parsed_frame] render_epp_response '/epp/contacts/check'
@contact = Epp::Contact.new(frame, current_user.registrar) end
@contact.add_legal_file_to_new(frame) def create
@contact.generate_code authorize! :create, Epp::Contact
frame = params[:parsed_frame]
@contact = Epp::Contact.new(frame, current_user.registrar)
if @contact.save @contact.add_legal_file_to_new(frame)
if !address_processing? && address_given? @contact.generate_code
@response_code = 1100
@response_description = t('epp.contacts.completed_without_address') if @contact.save
if !address_processing? && address_given?
@response_code = 1100
@response_description = t('epp.contacts.completed_without_address')
else
@response_code = 1000
@response_description = t('epp.contacts.completed')
end
render_epp_response '/epp/contacts/save'
else else
@response_code = 1000 handle_errors(@contact)
@response_description = t('epp.contacts.completed') end
end
def update
authorize! :update, @contact, @password
collected_data = ::Deserializers::Xml::ContactUpdate.new(params[:parsed_frame])
action = Actions::ContactUpdate.new(@contact,
collected_data.contact,
collected_data.legal_document,
collected_data.ident,
current_user)
if action.call
if !address_processing? && address_given?
@response_code = 1100
@response_description = t('epp.contacts.completed_without_address')
else
@response_code = 1000
@response_description = t('epp.contacts.completed')
end
render_epp_response 'epp/contacts/save'
else
handle_errors(@contact)
end
end
def delete
authorize! :delete, @contact, @password
if @contact.destroy_and_clean(params[:parsed_frame])
render_epp_response '/epp/contacts/delete'
else
handle_errors(@contact)
end
end
def renew
authorize! :renew, Epp::Contact
epp_errors << { code: '2101', msg: t(:'errors.messages.unimplemented_command') }
handle_errors
end
def transfer
authorize! :transfer, Epp::Contact
epp_errors << { code: '2101', msg: t(:'errors.messages.unimplemented_command') }
handle_errors
end
private
def find_password
@password = params[:parsed_frame].css('authInfo pw').text
end
def find_contact
code = params[:parsed_frame].css('id').text.strip.upcase
@contact = Epp::Contact.find_by!(code: code)
end
#
# Validations
#
def validate_info
@prefix = 'info > info >'
requires 'id'
end
def validate_check
@prefix = 'check > check >'
requires 'id'
end
def validate_create
@prefix = 'create > create >'
required_attributes = [
'postalInfo > name',
'voice',
'email'
]
address_attributes = [
'postalInfo > addr > street',
'postalInfo > addr > city',
'postalInfo > addr > pc',
'postalInfo > addr > cc',
]
required_attributes.concat(address_attributes) if address_processing?
requires(*required_attributes)
ident = params[:parsed_frame].css('ident')
if ident.present? && ident.attr('type').blank?
epp_errors << {
code: '2003',
msg: I18n.t('errors.messages.required_ident_attribute_missing', key: 'type')
}
end end
render_epp_response '/epp/contacts/save' if ident.present? && ident.text != 'birthday' && ident.attr('cc').blank?
else epp_errors << {
handle_errors(@contact) code: '2003',
end msg: I18n.t('errors.messages.required_ident_attribute_missing', key: 'cc')
end }
def update
authorize! :update, @contact, @password
frame = params[:parsed_frame]
if @contact.update_attributes(frame, current_user)
if !address_processing? && address_given?
@response_code = 1100
@response_description = t('epp.contacts.completed_without_address')
else
@response_code = 1000
@response_description = t('epp.contacts.completed')
end end
# if ident.present? && ident.attr('cc').blank?
render_epp_response 'epp/contacts/save'
else
handle_errors(@contact)
end
end
def delete
authorize! :delete, @contact, @password
if @contact.destroy_and_clean(params[:parsed_frame])
render_epp_response '/epp/contacts/delete'
else
handle_errors(@contact)
end
end
def renew
authorize! :renew, Epp::Contact
epp_errors << { code: '2101', msg: t(:'errors.messages.unimplemented_command') }
handle_errors
end
private
def find_password
@password = params[:parsed_frame].css('authInfo pw').text
end
def find_contact
code = params[:parsed_frame].css('id').text.strip.upcase
@contact = Epp::Contact.find_by_epp_code(code)
if @contact.blank?
epp_errors << {
code: '2303',
msg: t('errors.messages.epp_obj_does_not_exist'),
value: { obj: 'id', val: code }
}
fail CanCan::AccessDenied
end
@contact
end
#
# Validations
#
def validate_info
@prefix = 'info > info >'
requires 'id'
end
def validate_check
@prefix = 'check > check >'
requires 'id'
end
def validate_create
@prefix = 'create > create >'
required_attributes = [
'postalInfo > name',
'voice',
'email'
]
address_attributes = [
'postalInfo > addr > street',
'postalInfo > addr > city',
'postalInfo > addr > pc',
'postalInfo > addr > cc',
]
required_attributes.concat(address_attributes) if address_processing?
requires(*required_attributes)
ident = params[:parsed_frame].css('ident')
if ident.present? && ident.attr('type').blank?
epp_errors << {
code: '2003',
msg: I18n.t('errors.messages.required_ident_attribute_missing', key: 'type')
}
end
if ident.present? && ident.text != 'birthday' && ident.attr('cc').blank?
epp_errors << {
code: '2003',
msg: I18n.t('errors.messages.required_ident_attribute_missing', key: 'cc')
}
end
# if ident.present? && ident.attr('cc').blank?
# epp_errors << { # epp_errors << {
# code: '2003', # code: '2003',
# msg: I18n.t('errors.messages.required_ident_attribute_missing', key: 'cc') # msg: I18n.t('errors.messages.required_ident_attribute_missing', key: 'cc')
# } # }
# end # end
contact_org_disabled contact_org_disabled
fax_disabled fax_disabled
status_editing_disabled status_editing_disabled
@prefix = nil @prefix = nil
requires 'extension > extdata > ident' requires 'extension > extdata > ident'
end end
def validate_update def validate_update
@prefix = 'update > update >' @prefix = 'update > update >'
contact_org_disabled contact_org_disabled
fax_disabled fax_disabled
status_editing_disabled status_editing_disabled
requires 'id' requires 'id'
@prefix = nil @prefix = nil
end end
def validate_delete def validate_delete
@prefix = 'delete > delete >' @prefix = 'delete > delete >'
requires 'id' requires 'id'
@prefix = nil @prefix = nil
end end
def contact_org_disabled def contact_org_disabled
return true if ENV['contact_org_enabled'] == 'true' return true if ENV['contact_org_enabled'] == 'true'
return true if params[:parsed_frame].css('postalInfo org').text.blank? return true if params[:parsed_frame].css('postalInfo org').text.blank?
epp_errors << { epp_errors << {
code: '2306', code: '2306',
msg: "#{I18n.t(:contact_org_error)}: postalInfo > org [org]" msg: "#{I18n.t(:contact_org_error)}: postalInfo > org [org]"
} }
end end
def fax_disabled def fax_disabled
return true if ENV['fax_enabled'] == 'true' return true if ENV['fax_enabled'] == 'true'
return true if params[:parsed_frame].css('fax').text.blank? return true if params[:parsed_frame].css('fax').text.blank?
epp_errors << { epp_errors << {
code: '2306', code: '2306',
msg: "#{I18n.t(:contact_fax_error)}: fax [fax]" msg: "#{I18n.t(:contact_fax_error)}: fax [fax]"
} }
end end
def status_editing_disabled def status_editing_disabled
return true if Setting.client_status_editing_enabled return true if Setting.client_status_editing_enabled
return true if params[:parsed_frame].css('status').empty? return true if params[:parsed_frame].css('status').empty?
epp_errors << { epp_errors << {
code: '2306', code: '2306',
msg: "#{I18n.t(:client_side_status_editing_error)}: status [status]" msg: "#{I18n.t(:client_side_status_editing_error)}: status [status]"
} }
end end
def address_given? def address_given?
params[:parsed_frame].css('postalInfo addr').size != 0 params[:parsed_frame].css('postalInfo addr').size != 0
end end
def address_processing? def address_processing?
Contact.address_processing? Contact.address_processing?
end
end end
end end

View file

@ -1,92 +1,122 @@
class Epp::DomainsController < EppController module Epp
before_action :find_domain, only: %i[info renew update transfer delete] class DomainsController < BaseController
before_action :find_password, only: %i[info update transfer delete] before_action :find_domain, only: %i[info renew update transfer delete]
before_action :find_password, only: %i[info update transfer delete]
before_action :set_paper_trail_whodunnit
def info def info
authorize! :info, @domain, @password authorize! :info, @domain
@hosts = params[:parsed_frame].css('name').first['hosts'] || 'all' @hosts = params[:parsed_frame].css('name').first['hosts'] || 'all'
case @hosts sponsoring_registrar = (@domain.registrar == current_user.registrar)
when 'del' correct_transfer_code_provided = (@domain.transfer_code == @password)
@nameservers = @domain.delegated_nameservers.sort @reveal_full_details = (sponsoring_registrar || correct_transfer_code_provided)
when 'sub'
@nameservers = @domain.subordinate_nameservers.sort case @hosts
when 'all' when 'del'
@nameservers = @domain.nameservers.sort @nameservers = @domain.delegated_nameservers.sort
when 'sub'
@nameservers = @domain.subordinate_nameservers.sort
when 'all'
@nameservers = @domain.nameservers.sort
end
render_epp_response '/epp/domains/info'
end end
render_epp_response '/epp/domains/info' def create
end authorize! :create, Epp::Domain
def create if Domain.release_to_auction
authorize! :create, Epp::Domain request_domain_name = params[:parsed_frame].css('name').text.strip.downcase
domain_name = DNS::DomainName.new(SimpleIDN.to_unicode(request_domain_name))
if Domain.release_to_auction if domain_name.at_auction?
request_domain_name = params[:parsed_frame].css('name').text.strip.downcase epp_errors << {
domain_name = DNS::DomainName.new(SimpleIDN.to_unicode(request_domain_name)) code: '2306',
msg: 'Parameter value policy error: domain is at auction',
}
handle_errors
return
elsif domain_name.awaiting_payment?
epp_errors << {
code: '2003',
msg: 'Required parameter missing; reserved>pw element required for reserved domains',
}
handle_errors
return
elsif domain_name.pending_registration?
registration_code = params[:parsed_frame].css('reserved > pw').text
if domain_name.at_auction? if registration_code.empty?
throw :epp_error, epp_errors << {
code: '2306',
msg: 'Parameter value policy error: domain is at auction'
elsif domain_name.awaiting_payment?
throw :epp_error,
code: '2003', code: '2003',
msg: 'Required parameter missing; reserved>pw element required for reserved domains' msg: 'Required parameter missing; reserved>pw element is required',
elsif domain_name.pending_registration? }
registration_code = params[:parsed_frame].css('reserved > pw').text handle_errors
return
end
if registration_code.empty? unless domain_name.available_with_code?(registration_code)
throw :epp_error, epp_errors << {
code: '2003', code: '2202',
msg: 'Required parameter missing; reserved>pw element is required' msg: 'Invalid authorization information; invalid reserved>pw value',
}
handle_errors
return
end
end end
end
unless domain_name.available_with_code?(registration_code) @domain = Epp::Domain.new_from_epp(params[:parsed_frame], current_user)
throw :epp_error, handle_errors(@domain) and return if @domain.errors.any?
code: '2202', @domain.valid?
msg: 'Invalid authorization information; invalid reserved>pw value' @domain.errors.delete(:name_dirty) if @domain.errors[:puny_label].any?
handle_errors(@domain) and return if @domain.errors.any?
handle_errors and return unless balance_ok?('create') # loads pricelist in this method
ActiveRecord::Base.transaction do
@domain.add_legal_file_to_new(params[:parsed_frame])
if @domain.save # TODO: Maybe use validate: false here because we have already validated the domain?
current_user.registrar.debit!({
sum: @domain_pricelist.price.amount,
description: "#{I18n.t('create')} #{@domain.name}",
activity_type: AccountActivity::CREATE,
price: @domain_pricelist
})
if Domain.release_to_auction && domain_name.pending_registration?
active_auction = Auction.find_by(domain: domain_name.to_s,
status: Auction.statuses[:payment_received])
active_auction.domain_registered!
end
Dispute.close_by_domain(@domain.name)
render_epp_response '/epp/domains/create'
else
handle_errors(@domain)
end end
end end
end end
@domain = Epp::Domain.new_from_epp(params[:parsed_frame], current_user) def update
handle_errors(@domain) and return if @domain.errors.any? authorize! :update, @domain, @password
@domain.valid?
@domain.errors.delete(:name_dirty) if @domain.errors[:puny_label].any?
handle_errors(@domain) and return if @domain.errors.any?
handle_errors and return unless balance_ok?('create') # loads pricelist in this method
ActiveRecord::Base.transaction do updated = @domain.update(params[:parsed_frame], current_user)
@domain.add_legal_file_to_new(params[:parsed_frame]) (handle_errors(@domain) && return) unless updated
if @domain.save # TODO: Maybe use validate: false here because we have already validated the domain? pending = @domain.epp_pending_update.present?
current_user.registrar.debit!({ render_epp_response "/epp/domains/success#{'_pending' if pending}"
sum: @domain_pricelist.price.amount,
description: "#{I18n.t('create')} #{@domain.name}",
activity_type: AccountActivity::CREATE,
price: @domain_pricelist
})
if Domain.release_to_auction && domain_name.pending_registration?
active_auction = Auction.find_by(domain: domain_name.to_s,
status: Auction.statuses[:payment_received])
active_auction.domain_registered!
end
render_epp_response '/epp/domains/create'
else
handle_errors(@domain)
end
end end
end
def update def delete
authorize! :update, @domain, @password authorize! :delete, @domain, @password
begin
if @domain.update(params[:parsed_frame], current_user) (handle_errors(@domain) && return) unless @domain.can_be_deleted?
if @domain.epp_pending_update.present?
if @domain.epp_destroy(params[:parsed_frame], current_user.id)
if @domain.epp_pending_delete.present?
render_epp_response '/epp/domains/success_pending' render_epp_response '/epp/domains/success_pending'
else else
render_epp_response '/epp/domains/success' render_epp_response '/epp/domains/success'
@ -94,227 +124,219 @@ class Epp::DomainsController < EppController
else else
handle_errors(@domain) handle_errors(@domain)
end end
rescue => e
if @domain.errors.any?
handle_errors(@domain)
else
throw e
end
end end
end
def delete def check
authorize! :delete, @domain, @password authorize! :check, Epp::Domain
# all includes for bullet
@domain = Epp::Domain.where(id: @domain.id).includes(nameservers: :versions).first
handle_errors(@domain) and return unless @domain.can_be_deleted? domain_names = params[:parsed_frame].css('name').map(&:text)
@domains = Epp::Domain.check_availability(domain_names)
if @domain.epp_destroy(params[:parsed_frame], current_user.id) render_epp_response '/epp/domains/check'
if @domain.epp_pending_delete.present?
render_epp_response '/epp/domains/success_pending'
else
render_epp_response '/epp/domains/success'
end
else
handle_errors(@domain)
end end
end
def check def renew
authorize! :check, Epp::Domain authorize! :renew, @domain
domain_names = params[:parsed_frame].css('name').map(&:text) period_element = params[:parsed_frame].css('period').text
@domains = Epp::Domain.check_availability(domain_names) period = (period_element.to_i == 0) ? 1 : period_element.to_i
render_epp_response '/epp/domains/check' period_unit = Epp::Domain.parse_period_unit_from_frame(params[:parsed_frame]) || 'y'
end
def renew balance_ok?('renew', period, period_unit) # loading pricelist
authorize! :renew, @domain
period_element = params[:parsed_frame].css('period').text begin
period = (period_element.to_i == 0) ? 1 : period_element.to_i ActiveRecord::Base.transaction(isolation: :serializable) do
period_unit = Epp::Domain.parse_period_unit_from_frame(params[:parsed_frame]) || 'y' @domain.reload
balance_ok?('renew', period, period_unit) # loading pricelist success = @domain.renew(
params[:parsed_frame].css('curExpDate').text,
period, period_unit
)
begin if success
ActiveRecord::Base.transaction(isolation: :serializable) do unless balance_ok?('renew', period, period_unit)
@domain.reload handle_errors
fail ActiveRecord::Rollback
end
success = @domain.renew( current_user.registrar.debit!({
params[:parsed_frame].css('curExpDate').text, sum: @domain_pricelist.price.amount,
period, period_unit description: "#{I18n.t('renew')} #{@domain.name}",
) activity_type: AccountActivity::RENEW,
price: @domain_pricelist
})
if success render_epp_response '/epp/domains/renew'
unless balance_ok?('renew', period, period_unit) else
handle_errors handle_errors(@domain)
fail ActiveRecord::Rollback
end end
current_user.registrar.debit!({
sum: @domain_pricelist.price.amount,
description: "#{I18n.t('renew')} #{@domain.name}",
activity_type: AccountActivity::RENEW,
price: @domain_pricelist
})
render_epp_response '/epp/domains/renew'
else
handle_errors(@domain)
end end
rescue ActiveRecord::StatementInvalid => e
sleep rand / 100
retry
end end
rescue ActiveRecord::StatementInvalid => e
sleep rand / 100
retry
end
end
def transfer
authorize! :transfer, @domain, @password
action = params[:parsed_frame].css('transfer').first[:op]
if @domain.non_transferable?
throw :epp_error, {
code: '2304',
msg: I18n.t(:object_status_prohibits_operation)
}
end end
@domain_transfer = @domain.transfer(params[:parsed_frame], action, current_user) def transfer
authorize! :transfer, @domain
action = params[:parsed_frame].css('transfer').first[:op]
if @domain_transfer if @domain.non_transferable?
render_epp_response '/epp/domains/transfer'
else
epp_errors << {
code: '2303',
msg: I18n.t('no_transfers_found')
}
handle_errors
end
end
private
def validate_info
@prefix = 'info > info >'
requires('name')
optional_attribute 'name', 'hosts', values: %(all, sub, del, none)
end
def validate_create
if Domain.nameserver_required?
@prefix = 'create > create >'
requires 'name', 'ns', 'registrant', 'ns > hostAttr'
end
@prefix = 'extension > create >'
mutually_exclusive 'keyData', 'dsData'
@prefix = nil
requires 'extension > extdata > legalDocument'
optional_attribute 'period', 'unit', values: %w(d m y)
status_editing_disabled
end
def validate_update
if element_count('update > chg > registrant') > 0
requires 'extension > extdata > legalDocument'
end
@prefix = 'update > update >'
requires 'name'
status_editing_disabled
end
def validate_delete
requires 'extension > extdata > legalDocument'
@prefix = 'delete > delete >'
requires 'name'
end
def validate_check
@prefix = 'check > check >'
requires('name')
end
def validate_renew
@prefix = 'renew > renew >'
requires 'name', 'curExpDate'
optional_attribute 'period', 'unit', values: %w(d m y)
end
def validate_transfer
# period element is disabled for now
if params[:parsed_frame].css('period').any?
epp_errors << {
code: '2307',
msg: I18n.t(:unimplemented_object_service),
value: { obj: 'period' }
}
end
requires 'transfer > transfer'
@prefix = 'transfer > transfer >'
requires 'name'
@prefix = nil
requires_attribute 'transfer', 'op', values: %(approve, query, reject, request, cancel)
end
def find_domain
domain_name = params[:parsed_frame].css('name').text.strip.downcase
@domain = Epp::Domain.find_by_idn domain_name
unless @domain
epp_errors << {
code: '2303',
msg: I18n.t('errors.messages.epp_domain_not_found'),
value: { obj: 'name', val: domain_name }
}
fail CanCan::AccessDenied
end
@domain
end
def find_password
@password = params[:parsed_frame].css('authInfo pw').text
end
def status_editing_disabled
return true if Setting.client_status_editing_enabled
return true if params[:parsed_frame].css('status').empty?
epp_errors << {
code: '2306',
msg: "#{I18n.t(:client_side_status_editing_error)}: status [status]"
}
end
def balance_ok?(operation, period = nil, unit = nil)
@domain_pricelist = @domain.pricelist(operation, period.try(:to_i), unit)
if @domain_pricelist.try(:price) # checking if price list is not found
if current_user.registrar.balance < @domain_pricelist.price.amount
epp_errors << { epp_errors << {
code: '2304',
msg: I18n.t(:object_status_prohibits_operation),
}
handle_errors
return
end
provided_transfer_code = params[:parsed_frame].css('authInfo pw').text
wrong_transfer_code = provided_transfer_code != @domain.transfer_code
if wrong_transfer_code
epp_errors << {
code: '2202',
msg: 'Invalid authorization information',
}
handle_errors
return
end
@domain_transfer = @domain.transfer(params[:parsed_frame], action, current_user)
if @domain.errors[:epp_errors].any?
handle_errors(@domain)
return
end
if @domain_transfer
render_epp_response '/epp/domains/transfer'
else
epp_errors << {
code: '2303',
msg: I18n.t('no_transfers_found')
}
handle_errors
end
end
private
def validate_info
@prefix = 'info > info >'
requires('name')
optional_attribute 'name', 'hosts', values: %(all, sub, del, none)
end
def validate_create
if Domain.nameserver_required?
@prefix = 'create > create >'
requires 'name', 'ns', 'registrant', 'ns > hostAttr'
end
@prefix = 'extension > create >'
mutually_exclusive 'keyData', 'dsData'
@prefix = nil
requires 'extension > extdata > legalDocument' if current_user.legaldoc_mandatory?
optional_attribute 'period', 'unit', values: %w(d m y)
status_editing_disabled
end
def validate_update
if element_count('update > chg > registrant') > 0
requires 'extension > extdata > legalDocument' if current_user.legaldoc_mandatory?
end
@prefix = 'update > update >'
requires 'name'
status_editing_disabled
end
def validate_delete
@prefix = 'delete > delete >'
requires 'name'
end
def validate_check
@prefix = 'check > check >'
requires('name')
end
def validate_renew
@prefix = 'renew > renew >'
requires 'name', 'curExpDate'
optional_attribute 'period', 'unit', values: %w(d m y)
end
def validate_transfer
# period element is disabled for now
if params[:parsed_frame].css('period').any?
epp_errors << {
code: '2307',
msg: I18n.t(:unimplemented_object_service),
value: { obj: 'period' }
}
end
requires 'transfer > transfer'
@prefix = 'transfer > transfer >'
requires 'name'
@prefix = nil
requires_attribute 'transfer', 'op', values: %(approve, query, reject, request, cancel)
end
def find_domain
domain_name = params[:parsed_frame].css('name').text.strip.downcase
domain = Epp::Domain.find_by_idn(domain_name)
raise ActiveRecord::RecordNotFound unless domain
@domain = domain
end
def find_password
@password = params[:parsed_frame].css('authInfo pw').text
end
def status_editing_disabled
return true if Setting.client_status_editing_enabled
return true if check_client_hold
return true if params[:parsed_frame].css('status').empty?
epp_errors << {
code: '2306',
msg: "#{I18n.t(:client_side_status_editing_error)}: status [status]"
}
end
def check_client_hold
statuses = params[:parsed_frame].css('status').map { |element| element['s'] }
statuses == [::DomainStatus::CLIENT_HOLD]
end
def balance_ok?(operation, period = nil, unit = nil)
@domain_pricelist = @domain.pricelist(operation, period.try(:to_i), unit)
if @domain_pricelist.try(:price) # checking if price list is not found
if current_user.registrar.balance < @domain_pricelist.price.amount
epp_errors << {
code: '2104', code: '2104',
msg: I18n.t('billing_failure_credit_balance_low') msg: I18n.t('billing_failure_credit_balance_low')
}
return false
end
else
epp_errors << {
code: '2104',
msg: I18n.t(:active_price_missing_for_this_operation)
} }
return false return false
end end
else true
epp_errors << {
code: '2104',
msg: I18n.t(:active_price_missing_for_this_operation)
}
return false
end end
true
end end
end end

View file

@ -1,13 +1,10 @@
class Epp::ErrorsController < EppController module Epp
skip_authorization_check class ErrorsController < BaseController
skip_authorization_check
def error def error
epp_errors << { code: params[:code], msg: params[:msg] } epp_errors << { code: params[:code], msg: params[:msg] }
render_epp_response '/epp/error' render_epp_response '/epp/error'
end end
def not_found
epp_errors << { code: 2400, msg: t(:could_not_determine_object_type_check_xml_format_and_namespaces) }
render_epp_response '/epp/error'
end end
end end

View file

@ -1,61 +0,0 @@
class Epp::KeyrelaysController < EppController
skip_authorization_check # TODO: move authorization under ability
def keyrelay
# keyrelay temp turned off
@domain = find_domain
handle_errors(@domain) and return unless @domain
handle_errors(@domain) and return unless @domain.authenticate(params[:parsed_frame].css('pw').text)
handle_errors(@domain) and return unless @domain.keyrelay(params[:parsed_frame], current_user.registrar)
render_epp_response '/epp/shared/success'
end
private
def validate_keyrelay
@prefix = 'keyrelay >'
requires(
'name',
'keyData', 'keyData > pubKey', 'keyData > flags', 'keyData > protocol', 'keyData > alg',
'authInfo', 'authInfo > pw'
)
optional 'expiry > relative', duration_iso8601: true
optional 'expiry > absolute', date_time_iso8601: true
exactly_one_of 'expiry > relative', 'expiry > absolute'
end
def find_domain
domain_name = params[:parsed_frame].css('name').text.strip.downcase
# keyrelay temp turned off
epp_errors << {
code: '2307',
msg: I18n.t(:unimplemented_object_service),
value: { obj: 'name', val: domain_name }
}
nil
# end of keyrelay temp turned off
# domain = Epp::Domain.includes(:registrant).find_by(name: domain_name)
# unless domain
# epp_errors << {
# code: '2303',
# msg: I18n.t('errors.messages.epp_domain_not_found'),
# value: { obj: 'name', val: domain_name }
# }
# return nil
# end
# domain
end
def resource
@domain
end
end

View file

@ -1,61 +1,59 @@
class Epp::PollsController < EppController module Epp
skip_authorization_check # TODO: move authorization under ability class PollsController < BaseController
skip_authorization_check # TODO: move authorization under ability
def poll def poll
req_poll if params[:parsed_frame].css('poll').first['op'] == 'req' req_poll if params[:parsed_frame].css('poll').first['op'] == 'req'
ack_poll if params[:parsed_frame].css('poll').first['op'] == 'ack' ack_poll if params[:parsed_frame].css('poll').first['op'] == 'ack'
end
private
def req_poll
@notification = current_user.unread_notifications.order('created_at DESC').take
render_epp_response 'epp/poll/poll_no_messages' and return unless @notification
if @notification.attached_obj_type && @notification.attached_obj_id
begin
@object = Object.const_get(@notification.attached_obj_type).find(@notification.attached_obj_id)
rescue => problem
# the data model might be inconsistent; or ...
# this could happen if the registrar does not dequeue messages, and then the domain was deleted
# SELECT messages.id, domains.name, messages.body FROM messages LEFT OUTER
# JOIN domains ON attached_obj_id::INTEGER = domains.id
# WHERE attached_obj_type = 'Epp::Domain' AND name IS NULL;
Rails.logger.error 'orphan message, error ignored: ' + problem.to_s
# now we should dequeue or delete the messages avoid duplicate log alarms
end
end end
if @notification.attached_obj_type == 'Keyrelay' private
render_epp_response 'epp/poll/poll_keyrelay'
else def req_poll
@notification = current_user.unread_notifications.order('created_at DESC').take
render_epp_response 'epp/poll/poll_no_messages' and return unless @notification
if @notification.attached_obj_type && @notification.attached_obj_id
begin
@object = Object.const_get(@notification.attached_obj_type).find(@notification.attached_obj_id)
rescue => problem
# the data model might be inconsistent; or ...
# this could happen if the registrar does not dequeue messages, and then the domain was deleted
# SELECT messages.id, domains.name, messages.body FROM messages LEFT OUTER
# JOIN domains ON attached_obj_id::INTEGER = domains.id
# WHERE attached_obj_type = 'Epp::Domain' AND name IS NULL;
Rails.logger.error 'orphan message, error ignored: ' + problem.to_s
# now we should dequeue or delete the messages avoid duplicate log alarms
end
end
render_epp_response 'epp/poll/poll_req' render_epp_response 'epp/poll/poll_req'
end end
end
def ack_poll def ack_poll
@notification = current_user.unread_notifications.find_by(id: params[:parsed_frame].css('poll').first['msgID']) @notification = current_user.unread_notifications.find_by(id: params[:parsed_frame].css('poll').first['msgID'])
unless @notification unless @notification
epp_errors << { epp_errors << {
code: '2303', code: '2303',
msg: I18n.t('message_was_not_found'), msg: I18n.t('message_was_not_found'),
value: { obj: 'msgID', val: params[:parsed_frame].css('poll').first['msgID'] } value: { obj: 'msgID', val: params[:parsed_frame].css('poll').first['msgID'] }
} }
handle_errors and return handle_errors and return
end
handle_errors(@notification) and return unless @notification.mark_as_read
render_epp_response 'epp/poll/poll_ack'
end end
handle_errors(@notification) and return unless @notification.mark_as_read def validate_poll
render_epp_response 'epp/poll/poll_ack' requires_attribute 'poll', 'op', values: %(ack req), allow_blank: true
end end
def validate_poll def resource
requires_attribute 'poll', 'op', values: %(ack req), allow_blank: true @notification
end end
def resource
@notification
end end
end end

View file

@ -1,138 +1,144 @@
class Epp::SessionsController < EppController module Epp
skip_authorization_check only: [:hello, :login, :logout] class SessionsController < BaseController
skip_authorization_check only: [:hello, :login, :logout]
before_action :set_paper_trail_whodunnit
def hello def hello
render_epp_response('greeting') render_epp_response('greeting')
end
def login
success = true
@api_user = ApiUser.find_by(login_params)
webclient_request = ENV['webclient_ips'].split(',').map(&:strip).include?(request.ip)
if webclient_request && !Rails.env.test? && !Rails.env.development?
client_md5 = Certificate.parse_md_from_string(request.env['HTTP_SSL_CLIENT_CERT'])
server_md5 = Certificate.parse_md_from_string(File.read(ENV['cert_path']))
if client_md5 != server_md5
epp_errors << {
msg: 'Authentication error; server closing connection (certificate is not valid)',
code: '2501'
}
success = false
end
end end
if !Rails.env.development? && (!webclient_request && @api_user) def login
unless @api_user.api_pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'], request.env['HTTP_SSL_CLIENT_S_DN_CN']) success = true
epp_errors << { @api_user = ApiUser.find_by(login_params)
msg: 'Authentication error; server closing connection (certificate is not valid)',
code: '2501'
}
success = false webclient_request = ENV['webclient_ips'].split(',').map(&:strip).include?(request.ip)
end if webclient_request && !Rails.env.test? && !Rails.env.development?
end client_md5 = Certificate.parse_md_from_string(request.env['HTTP_SSL_CLIENT_CERT'])
if ENV['cert_path'].blank?
raise 'webclient cert (cert_path) missing, registrar (r)epp disabled'
end
if success && !@api_user server_md5 = Certificate.parse_md_from_string(File.read(ENV['cert_path']))
epp_errors << { if client_md5 != server_md5
msg: 'Authentication error; server closing connection (API user not found)', epp_errors << {
code: '2501' msg: 'Authentication error; server closing connection (certificate is not valid)',
} code: '2501'
}
success = false success = false
end
if success && !@api_user.try(:active)
epp_errors << {
msg: 'Authentication error; server closing connection (API user is not active)',
code: '2501'
}
success = false
end
if success && @api_user.cannot?(:create, :epp_login)
epp_errors << {
msg: 'Authentication error; server closing connection (API user does not have epp role)',
code: '2501'
}
success = false
end
if success && !ip_white?
epp_errors << {
msg: 'Authentication error; server closing connection (IP is not whitelisted)',
code: '2501'
}
success = false
end
if success && EppSession.limit_reached?(@api_user.registrar)
epp_errors << {
msg: 'Authentication error; server closing connection (connection limit reached)',
code: '2501'
}
success = false
end
if success
if params[:parsed_frame].css('newPW').first
unless @api_user.update(plain_text_password: params[:parsed_frame].css('newPW').first.text)
response.headers['X-EPP-Returncode'] = '2500'
handle_errors(@api_user) and return
end end
end end
epp_session = EppSession.new if !Rails.env.development? && (!webclient_request && @api_user)
epp_session.session_id = epp_session_id unless @api_user.pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'],
epp_session.user = @api_user request.env['HTTP_SSL_CLIENT_S_DN_CN'])
epp_session.save! epp_errors << {
render_epp_response('login_success') msg: 'Authentication error; server closing connection (certificate is not valid)',
else code: '2501'
response.headers['X-EPP-Returncode'] = '2500' }
handle_errors
success = false
end
end
if success && !@api_user
epp_errors << {
msg: 'Authentication error; server closing connection (API user not found)',
code: '2501'
}
success = false
end
if success && !@api_user.try(:active)
epp_errors << {
msg: 'Authentication error; server closing connection (API user is not active)',
code: '2501'
}
success = false
end
if success && @api_user.cannot?(:create, :epp_login)
epp_errors << {
msg: 'Authentication error; server closing connection (API user does not have epp role)',
code: '2501'
}
success = false
end
if success && !ip_white?
epp_errors << {
msg: 'Authentication error; server closing connection (IP is not whitelisted)',
code: '2501'
}
success = false
end
if success && EppSession.limit_reached?(@api_user.registrar)
epp_errors << {
msg: 'Authentication error; server closing connection (connection limit reached)',
code: '2501'
}
success = false
end
if success
if params[:parsed_frame].css('newPW').first
unless @api_user.update(plain_text_password: params[:parsed_frame].css('newPW').first.text)
handle_errors(@api_user) and return
end
end
epp_session = EppSession.new
epp_session.session_id = epp_session_id
epp_session.user = @api_user
epp_session.save!
render_epp_response('login_success')
else
handle_errors
end end
end end
def ip_white? def ip_white?
webclient_request = ENV['webclient_ips'].split(',').map(&:strip).include?(request.ip) webclient_request = ENV['webclient_ips'].split(',').map(&:strip).include?(request.ip)
return true if webclient_request return true if webclient_request
if @api_user if @api_user
return false unless @api_user.registrar.api_ip_white?(request.ip) return false unless @api_user.registrar.api_ip_white?(request.ip)
end end
true true
end
def logout
unless signed_in?
epp_errors << {
code: 2201,
msg: 'Authorization error'
}
handle_errors
return
end end
@api_user = current_user # cache current_user for logging def logout
epp_session.destroy unless signed_in?
response.headers['X-EPP-Returncode'] = '1500' epp_errors << {
render_epp_response('logout') code: 2201,
msg: 'Authorization error'
}
handle_errors
return
end
@api_user = current_user # cache current_user for logging
epp_session.destroy
render_epp_response('logout')
end end
### HELPER METHODS ### ### HELPER METHODS ###
def login_params def login_params
user = params[:parsed_frame].css('clID').first.text user = params[:parsed_frame].css('clID').first.text
pw = params[:parsed_frame].css('pw').first.text pw = params[:parsed_frame].css('pw').first.text
{ username: user, plain_text_password: pw } { username: user, plain_text_password: pw }
end end
private private
def resource
@api_user def resource
@api_user
end
end end
end end

View file

@ -1,417 +0,0 @@
class EppController < ApplicationController
layout false
protect_from_forgery with: :null_session
skip_before_action :verify_authenticity_token
before_action :ensure_session_id_passed
before_action :generate_svtrid
before_action :latin_only
before_action :validate_against_schema
before_action :validate_request
before_action :update_epp_session, if: 'signed_in?'
around_action :catch_epp_errors
helper_method :current_user
helper_method :resource
def validate_against_schema
return if ['hello', 'error', 'keyrelay'].include?(params[:action])
schema.validate(params[:nokogiri_frame]).each do |error|
epp_errors << {
code: 2001,
msg: error
}
response.headers['X-EPP-Returncode'] = '2200'
end
handle_errors and return if epp_errors.any?
end
def catch_epp_errors
err = catch(:epp_error) do
yield
nil
end
return unless err
@errors = [err]
handle_errors
end
rescue_from StandardError do |e|
@errors ||= []
if e.class == CanCan::AccessDenied
if @errors.blank?
@errors = [{
msg: t('errors.messages.epp_authorization_error'),
code: '2201'
}]
end
else
if @errors.blank?
@errors = [{
msg: 'Internal error.',
code: '2400'
}]
end
if Rails.env.test? || Rails.env.development?
puts e.backtrace.reverse.join("\n")
puts "\n BACKTRACE REVERSED!\n"
puts "\n FROM-EPP-RESCUE: #{e.message}\n\n\n"
else
logger.error "FROM-EPP-RESCUE: #{e.message}"
logger.error e.backtrace.join("\n")
end
end
render_epp_response '/epp/error'
end
def schema
EPP_ALL_SCHEMA
end
def generate_svtrid
@svTRID = "ccReg-#{format('%010d', rand(10**10))}"
end
def params_hash # TODO: THIS IS DEPRECATED AND WILL BE REMOVED IN FUTURE
@params_hash ||= Hash.from_xml(params[:frame]).with_indifferent_access
end
def epp_session
EppSession.find_by(session_id: epp_session_id)
end
def current_user
return unless signed_in?
epp_session.user
end
# ERROR + RESPONSE HANDLING
def epp_errors
@errors ||= []
end
def handle_errors(obj = nil)
@errors ||= []
if obj
obj.construct_epp_errors
@errors += obj.errors[:epp_errors]
end
if params[:parsed_frame].at_css('update')
@errors.each_with_index do |errors, index|
if errors[:code] == '2304' &&
errors[:value].present? &&
errors[:value][:val] == DomainStatus::SERVER_DELETE_PROHIBITED &&
errors[:value][:obj] == 'status'
@errors[index][:value][:val] = DomainStatus::PENDING_UPDATE
end
end
end
# for debugging
if @errors.blank?
@errors << {
code: '1',
msg: 'handle_errors was executed when there were actually no errors'
}
end
@errors.uniq!
logger.error "\nFOLLOWING ERRORS OCCURRED ON EPP QUERY:"
logger.error @errors.inspect
logger.error "\n"
# Requested by client, ticket #2688
# Known issues: error request is exactly 1 second slower and server can handle less load
sleep 1 if !Rails.env.test? || !Rails.env.development?
render_epp_response '/epp/error'
end
def render_epp_response(*args)
@response = render_to_string(*args)
render xml: @response
write_to_epp_log
end
# VALIDATION
def latin_only
return true if params['frame'].blank?
if params['frame'].match?(/\A[\p{Latin}\p{Z}\p{P}\p{S}\p{Cc}\p{Cf}\w_\'\+\-\.\(\)\/]*\Z/i)
return true
end
epp_errors << {
msg: 'Parameter value policy error. Allowed only Latin characters.',
code: '2306'
}
handle_errors and return false
end
# VALIDATION
def validate_request
validation_method = "validate_#{params[:action]}"
return unless respond_to?(validation_method, true)
send(validation_method)
# validate legal document's type here because it may be in most of the requests
@prefix = nil
if element_count('extdata > legalDocument').positive?
requires_attribute('extdata > legalDocument', 'type', values: LegalDocument::TYPES, policy: true)
end
handle_errors and return if epp_errors.any?
end
# let's follow grape's validations: https://github.com/intridea/grape/#parameter-validation-and-coercion
# Adds error to epp_errors if element is missing or blank
# Returns last element of selectors if it exists
#
# requires 'transfer'
#
# TODO: Add possibility to pass validations / options in the method
def requires(*selectors)
options = selectors.extract_options!
allow_blank = options[:allow_blank] ||= false # allow_blank is false by default
el, missing = nil, nil
selectors.each do |selector|
full_selector = [@prefix, selector].compact.join(' ')
attr = selector.split('>').last.strip.underscore
el = params[:parsed_frame].css(full_selector).first
if allow_blank
missing = el.nil?
else
missing = el.present? ? el.text.blank? : true
end
epp_errors << {
code: '2003',
msg: I18n.t('errors.messages.required_parameter_missing', key: "#{full_selector} [#{attr}]")
} if missing
end
missing ? false : el # return last selector if it was present
end
# Adds error to epp_errors if element or attribute is missing or attribute attribute is not one
# of the values
#
# requires_attribute 'transfer', 'op', values: %(approve, query, reject)
def requires_attribute(element_selector, attribute_selector, options)
element = requires(element_selector, allow_blank: options[:allow_blank])
return unless element
attribute = element[attribute_selector]
unless attribute
epp_errors << {
code: '2003',
msg: I18n.t('errors.messages.required_parameter_missing', key: attribute_selector)
}
return
end
return if options[:values].include?(attribute)
if options[:policy]
epp_errors << {
code: '2306',
msg: I18n.t('attribute_is_invalid', attribute: attribute_selector)
}
else
epp_errors << {
code: '2004',
msg: I18n.t('parameter_value_range_error', key: attribute_selector)
}
end
end
def optional_attribute(element_selector, attribute_selector, options)
full_selector = [@prefix, element_selector].compact.join(' ')
element = params[:parsed_frame].css(full_selector).first
return unless element
attribute = element[attribute_selector]
return if (attribute && options[:values].include?(attribute)) || !attribute
epp_errors << {
code: '2306',
msg: I18n.t('attribute_is_invalid', attribute: attribute_selector)
}
end
def exactly_one_of(*selectors)
full_selectors = create_full_selectors(*selectors)
return if element_count(*full_selectors, use_prefix: false) == 1
epp_errors << {
code: '2306',
msg: I18n.t(:exactly_one_parameter_required, params: full_selectors.join(' OR '))
}
end
def mutually_exclusive(*selectors)
full_selectors = create_full_selectors(*selectors)
return if element_count(*full_selectors, use_prefix: false) <= 1
epp_errors << {
code: '2306',
msg: I18n.t(:mutally_exclusive_params, params: full_selectors.join(', '))
}
end
def optional(selector, *validations)
full_selector = [@prefix, selector].compact.join(' ')
el = params[:parsed_frame].css(full_selector).first
return unless el&.text.present?
value = el.text
validations.each do |x|
validator = "#{x.first[0]}_validator".camelize.constantize
err = validator.validate_epp(selector.split(' ').last, value)
epp_errors << err if err
end
end
# Returns how many elements were present in the request
# if use_prefix is true, @prefix will be prepended to selectors e.g create > create > name
# default is true
#
# @prefix = 'create > create >'
# element_count 'name', 'registrar', use_prefix: false
# => 2
def element_count(*selectors)
options = selectors.extract_options!
use_prefix = options[:use_prefix] != false # use_prefix is true by default
present_count = 0
selectors.each do |selector|
full_selector = use_prefix ? [@prefix, selector].compact.join(' ') : selector
el = params[:parsed_frame].css(full_selector).first
present_count += 1 if el && el.text.present?
end
present_count
end
def create_full_selectors(*selectors)
selectors.map { |x| [@prefix, x].compact.join(' ') }
end
def xml_attrs_present?(ph, attributes) # TODO: THIS IS DEPRECATED AND WILL BE REMOVED IN FUTURE
attributes.each do |x|
epp_errors << {
code: '2003',
msg: I18n.t('errors.messages.required_parameter_missing', key: x.last)
} unless has_attribute(ph, x)
end
epp_errors.empty?
end
def has_attribute(ph, path) # TODO: THIS IS DEPRECATED AND WILL BE REMOVED IN FUTURE
path.reduce(ph) do |location, key|
location.respond_to?(:keys) ? location[key] : nil
end
end
def write_to_epp_log
request_command = params[:command] || params[:action] # error receives :command, other methods receive :action
frame = params[:raw_frame] || params[:frame]
# filter pw
if request_command == 'login' && frame.present?
frame.gsub!(/pw>.+<\//, 'pw>[FILTERED]</')
end
trimmed_request = frame.gsub(/<eis:legalDocument([^>]+)>([^<])+<\/eis:legalDocument>/, "<eis:legalDocument>[FILTERED]</eis:legalDocument>") if frame.present?
ApiLog::EppLog.create({
request: trimmed_request,
request_command: request_command,
request_successful: epp_errors.empty?,
request_object: resource ? "#{params[:epp_object_type]}: #{resource.class} - #{resource.id} - #{resource.name}" : params[:epp_object_type],
response: @response,
api_user_name: @api_user.try(:username) || current_user.try(:username) || 'api-public',
api_user_registrar: @api_user.try(:registrar).try(:to_s) || current_user.try(:registrar).try(:to_s),
ip: request.ip,
uuid: request.uuid
})
end
def resource
name = self.class.to_s.sub("Epp::","").sub("Controller","").underscore.singularize
instance_variable_get("@#{name}")
end
private
def signed_in?
epp_session
end
def epp_session_id
cookies[:session] # Passed by mod_epp https://github.com/mod-epp/mod-epp#requestscript-interface
end
def ensure_session_id_passed
raise 'EPP session id is empty' unless epp_session_id.present?
end
def update_epp_session
iptables_counter_update
if session_timeout_reached?
@api_user = current_user # cache current_user for logging
epp_session.destroy
response.headers['X-EPP-Returncode'] = '1500'
epp_errors << {
msg: t('session_timeout'),
code: '2201'
}
handle_errors and return
else
epp_session.update_column(:updated_at, Time.zone.now)
end
end
def session_timeout_reached?
timeout = 5.minutes
epp_session.updated_at < (Time.zone.now - timeout)
end
def iptables_counter_update
return if ENV['iptables_counter_enabled'].blank? && ENV['iptables_counter_enabled'] != 'true'
return if current_user.blank?
counter_update(current_user.registrar_code, ENV['iptables_server_ip'])
end
def counter_update(registrar_code, ip)
counter_proc = "/proc/net/xt_recent/#{registrar_code}"
begin
File.open(counter_proc, 'a') do |f|
f.puts "+#{ip}"
end
rescue Errno::ENOENT => e
logger.error "IPTABLES COUNTER UPDATE: cannot open #{counter_proc}: #{e}"
rescue Errno::EACCES => e
logger.error "IPTABLES COUNTER UPDATE: no permission #{counter_proc}: #{e}"
rescue IOError => e
logger.error "IPTABLES COUNTER UPDATE: cannot write #{ip} to #{counter_proc}: #{e}"
end
end
end

View file

@ -1,10 +1,12 @@
class Registrant::ContactsController < RegistrantController class Registrant::ContactsController < RegistrantController
helper_method :domain helper_method :domain
helper_method :fax_enabled? helper_method :fax_enabled?
helper_method :domain_filter_params
skip_authorization_check only: %i[edit update] skip_authorization_check only: %i[edit update]
before_action :set_contact, only: [:show]
def show def show
@contact = current_user_contacts.find(params[:id]) @requester_contact = Contact.find_by(ident: current_registrant_user.ident)
authorize! :read, @contact authorize! :read, @contact
end end
@ -29,6 +31,13 @@ class Registrant::ContactsController < RegistrantController
private private
def set_contact
id = params[:id]
contact = domain.contacts.find_by(id: id) || current_user_contacts.find_by(id: id)
contact ||= Contact.find_by(id: id, ident: domain.registrant.ident)
@contact = contact
end
def domain def domain
current_user_domains.find(params[:domain_id]) current_user_domains.find(params[:domain_id])
end end
@ -99,4 +108,8 @@ class Registrant::ContactsController < RegistrantController
http.request(request) http.request(request)
end end
end end
def domain_filter_params
params.permit(:domain_filter)
end
end end

View file

@ -4,6 +4,7 @@ class Registrant::DomainDeleteConfirmsController < RegistrantController
def show def show
return if params[:confirmed] || params[:rejected] return if params[:confirmed] || params[:rejected]
@domain = Domain.find(params[:id]) @domain = Domain.find(params[:id])
@domain = nil unless @domain.registrant_delete_confirmable?(params[:token]) @domain = nil unless @domain.registrant_delete_confirmable?(params[:token])
end end
@ -16,28 +17,28 @@ class Registrant::DomainDeleteConfirmsController < RegistrantController
end end
@registrant_verification = RegistrantVerification.new(domain_id: @domain.id, @registrant_verification = RegistrantVerification.new(domain_id: @domain.id,
domain_name: @domain.name,
verification_token: params[:token]) verification_token: params[:token])
initiator = current_registrant_user ? current_registrant_user.username : initiator = current_registrant_user ? current_registrant_user.username :
t(:user_not_authenticated) t(:user_not_authenticated)
if params[:rejected] confirmed = params[:confirmed] ? true : false
if @registrant_verification.domain_registrant_delete_reject!("email link #{initiator}") action = if confirmed
flash[:notice] = t(:registrant_domain_verification_rejected) @registrant_verification.domain_registrant_delete_confirm!("email link #{initiator}")
redirect_to registrant_domain_delete_confirm_path(@domain.id, rejected: true) else
else @registrant_verification.domain_registrant_delete_reject!("email link #{initiator}")
flash[:alert] = t(:registrant_domain_delete_rejected_failed) end
return render 'show'
end fail_msg = t("registrant_domain_delete_#{confirmed ? 'confirmed' : 'rejected'}_failed".to_sym)
elsif params[:confirmed] success_msg = t("registrant_domain_verification_#{confirmed ? 'confirmed' : 'rejected'}".to_sym)
if @registrant_verification.domain_registrant_delete_confirm!("email link #{initiator}")
flash[:notice] = t(:registrant_domain_verification_confirmed) flash[:alert] = action ? success_msg : fail_msg
redirect_to registrant_domain_delete_confirm_path(@domain.id, confirmed: true) (render 'show' && return) unless action
else
flash[:alert] = t(:registrant_domain_delete_confirmed_failed) if confirmed
return render 'show' redirect_to registrant_domain_delete_confirm_path(@domain.id, confirmed: true)
end else
redirect_to registrant_domain_delete_confirm_path(@domain.id, rejected: true)
end end
end end
end end

View file

@ -16,7 +16,6 @@ class Registrant::DomainUpdateConfirmsController < RegistrantController
end end
@registrant_verification = RegistrantVerification.new(domain_id: @domain.id, @registrant_verification = RegistrantVerification.new(domain_id: @domain.id,
domain_name: @domain.name,
verification_token: params[:token]) verification_token: params[:token])
initiator = current_registrant_user ? current_registrant_user.username : initiator = current_registrant_user ? current_registrant_user.username :
@ -32,6 +31,8 @@ class Registrant::DomainUpdateConfirmsController < RegistrantController
end end
elsif params[:confirmed] elsif params[:confirmed]
if @registrant_verification.domain_registrant_change_confirm!("email link, #{initiator}") if @registrant_verification.domain_registrant_change_confirm!("email link, #{initiator}")
Dispute.close_by_domain(@domain.name) if @domain.disputed?
flash[:notice] = t(:registrant_domain_verification_confirmed) flash[:notice] = t(:registrant_domain_verification_confirmed)
redirect_to registrant_domain_update_confirm_path(@domain.id, confirmed: true) redirect_to registrant_domain_update_confirm_path(@domain.id, confirmed: true)
else else

View file

@ -4,11 +4,29 @@ class Registrant::DomainsController < RegistrantController
params[:q] ||= {} params[:q] ||= {}
normalize_search_parameters do normalize_search_parameters do
@q = current_user_domains.search(params[:q]) @q = current_user_domains.search(search_params)
@domains = @q.result.page(params[:page])
end end
@domains = @domains.per(params[:results_per_page]) if params[:results_per_page].to_i.positive? domains = @q.result
respond_to do |format|
format.html do
@domains = domains.page(params[:page])
domains_per_page = params[:results_per_page].to_i
@domains = @domains.per(domains_per_page) if domains_per_page.positive?
end
format.csv do
raw_csv = @q.result.to_csv
send_data raw_csv, filename: 'domains.csv', type: "#{Mime[:csv]}; charset=utf-8"
end
format.pdf do
view = ActionView::Base.new(ActionController::Base.view_paths, domains: domains)
raw_html = view.render(file: 'registrant/domains/list_pdf', layout: false)
raw_pdf = domains.pdf(raw_html)
send_data raw_pdf, filename: 'domains.pdf'
end
end
end end
def show def show
@ -32,23 +50,6 @@ class Registrant::DomainsController < RegistrantController
end end
end end
def download_list
authorize! :view, :registrant_domains
params[:q] ||= {}
normalize_search_parameters do
@q = current_user_domains.search(params[:q])
@domains = @q
end
respond_to do |format|
format.csv { render text: @domains.result.to_csv }
format.pdf do
pdf = @domains.result.pdf(render_to_string('registrant/domains/download_list', layout: false))
send_data pdf, filename: 'domains.pdf'
end
end
end
private private
def normalize_search_parameters def normalize_search_parameters
@ -70,4 +71,9 @@ class Registrant::DomainsController < RegistrantController
registrant_domain_delete_confirm_url(token: domain.registrant_verification_token) registrant_domain_delete_confirm_url(token: domain.registrant_verification_token)
end end
end end
def search_params
params.require(:q).permit(:name_matches, :registrant_ident_eq, :valid_to_gteq, :valid_to_lteq,
:results_per_page)
end
end end

View file

@ -1,5 +1,6 @@
class RegistrantController < ApplicationController class RegistrantController < ApplicationController
before_action :authenticate_registrant_user! before_action :authenticate_registrant_user!
before_action :set_paper_trail_whodunnit
layout 'registrant/application' layout 'registrant/application'
include Registrant::ApplicationHelper include Registrant::ApplicationHelper

View file

@ -6,6 +6,7 @@ class Registrar
before_action :check_ip_restriction before_action :check_ip_restriction
helper_method :depp_controller? helper_method :depp_controller?
helper_method :head_title_sufix helper_method :head_title_sufix
before_action :set_paper_trail_whodunnit
protected protected

View file

@ -3,6 +3,7 @@ class Registrar
before_action :init_epp_contact before_action :init_epp_contact
helper_method :address_processing? helper_method :address_processing?
helper_method :ident_types helper_method :ident_types
helper_method :domain_filter_params
def index def index
authorize! :view, Depp::Contact authorize! :view, Depp::Contact
@ -16,51 +17,40 @@ class Registrar
search_params[:registrant_domains_id_not_null] = 1 search_params[:registrant_domains_id_not_null] = 1
end end
if search_params.length == 1 && search_params[:name_matches].present? contacts = current_registrar_user.registrar.contacts.includes(:registrar)
@contacts = Contact.find_by(name: search_params[:name_matches]) status_list = params[:statuses_contains]
end
if params[:statuses_contains] if status_list
contacts = current_registrar_user.registrar.contacts.includes(:registrar).where( contacts_ids = contacts.select { |c| (c.statuses & status_list.to_a) == status_list.to_a }
"contacts.statuses @> ?::varchar[]", "{#{params[:statuses_contains].join(',')}}" .map(&:id)
) contacts = contacts.where(id: contacts_ids)
else
contacts = current_registrar_user.registrar.contacts.includes(:registrar)
end end
normalize_search_parameters do normalize_search_parameters do
@q = contacts.search(search_params) @q = contacts.search(search_params)
@contacts = @q.result(distinct: :true).page(params[:page])
end end
@contacts = @contacts.per(params[:results_per_page]) if params[:results_per_page].to_i.positive? contacts = @q.result
end
def download_list
authorize! :view, Depp::Contact
params[:q] ||= {}
params[:q].delete_if { |_k, v| v.blank? }
if params[:q].length == 1 && params[:q][:name_matches].present?
@contacts = Contact.find_by(name: params[:q][:name_matches])
end
contacts = current_registrar_user.registrar.contacts.includes(:registrar)
contacts = contacts.filter_by_states(params[:statuses_contains]) if params[:statuses_contains]
normalize_search_parameters do
@q = contacts.search(params[:q])
@contacts = @q.result
end
respond_to do |format| respond_to do |format|
format.csv { render text: @contacts.to_csv } 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 = contacts.to_csv
send_data raw_csv, filename: 'contacts.csv', type: "#{Mime[:csv]}; charset=utf-8"
end
format.pdf do format.pdf do
pdf = @contacts.pdf(render_to_string('registrar/contacts/download_list', layout: false)) view = ActionView::Base.new(ActionController::Base.view_paths, contacts: contacts)
send_data pdf, filename: 'contacts.pdf' view.class_eval { include ::ApplicationHelper }
raw_html = view.render(file: 'registrar/contacts/list_pdf', layout: false)
raw_pdf = contacts.pdf(raw_html)
send_data raw_pdf, filename: 'contacts.pdf'
end end
end end
end end
def new def new
@ -80,7 +70,7 @@ class Registrar
def create def create
authorize! :create, Depp::Contact authorize! :create, Depp::Contact
@contact = Depp::Contact.new(params[:depp_contact]) @contact = Depp::Contact.new(contact_params)
if @contact.save if @contact.save
redirect_to registrar_contact_url(@contact.id) redirect_to registrar_contact_url(@contact.id)
@ -91,9 +81,9 @@ class Registrar
def update def update
authorize! :edit, Depp::Contact authorize! :edit, Depp::Contact
@contact = Depp::Contact.new(params[:depp_contact]) @contact = Depp::Contact.new(contact_params)
if @contact.update_attributes(params[:depp_contact]) if @contact.update_attributes(contact_params)
redirect_to registrar_contact_url(@contact.id) redirect_to registrar_contact_url(@contact.id)
else else
render 'edit' render 'edit'
@ -107,7 +97,7 @@ class Registrar
def destroy def destroy
authorize! :delete, Depp::Contact authorize! :delete, Depp::Contact
@contact = Depp::Contact.new(params[:depp_contact]) @contact = Depp::Contact.new(contact_params_for_delete)
if @contact.delete if @contact.delete
redirect_to registrar_contacts_url, notice: t(:destroyed) redirect_to registrar_contacts_url, notice: t(:destroyed)
@ -116,6 +106,12 @@ class Registrar
end end
end end
protected
def domain_filter_params
params.permit(:domain_filter)
end
private private
def init_epp_contact def init_epp_contact
@ -143,5 +139,22 @@ class Registrar
def ident_types def ident_types
Contact::Ident.types Contact::Ident.types
end 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
end end

View file

@ -6,7 +6,7 @@ class Registrar
raise 'Cannot switch to unlinked user' unless current_registrar_user.linked_with?(new_user) raise 'Cannot switch to unlinked user' unless current_registrar_user.linked_with?(new_user)
sign_in(:registrar_user, new_user) sign_in(:registrar_user, new_user)
redirect_to :back, notice: t('.switched', new_user: new_user) redirect_back(fallback_location: root_path, notice: t('.switched', new_user: new_user))
end end
private private

View file

@ -2,16 +2,17 @@ class Registrar
class DomainsController < DeppController class DomainsController < DeppController
before_action :init_domain, except: :new before_action :init_domain, except: :new
helper_method :contacts helper_method :contacts
helper_method :search_params
def index def index
authorize! :view, Depp::Domain authorize! :view, Depp::Domain
params[:q] ||= {} if search_params.to_h.delete_if { |_key, value| value.blank? }.length == 1 &&
params[:q].delete_if { |_k, v| v.blank? } search_params[:name_matches].present?
if params[:q].length == 1 && params[:q][:name_matches].present? domain = Domain.find_by(name: search_params[:name_matches])
@domain = Domain.find_by(name: params[:q][:name_matches])
if @domain if domain
redirect_to info_registrar_domains_url(domain_name: @domain.name) and return redirect_to info_registrar_domains_url(domain_name: domain.name) and return
end end
end end
@ -24,15 +25,15 @@ class Registrar
end end
normalize_search_parameters do normalize_search_parameters do
@q = domains.search(params[:q]) @q = domains.search(search_params)
@domains = @q.result.page(params[:page]) @domains = @q.result.page(params[:page])
if @domains.count == 0 && params[:q][:name_matches] !~ /^%.+%$/
# if we do not get any results, add wildcards to the name field and search again # if we do not get any results, add wildcards to the name field and search again
n_cache = params[:q][:name_matches] if @domains.count == 0 && search_params[:name_matches] !~ /^%.+%$/
params[:q][:name_matches] = "%#{params[:q][:name_matches]}%" new_search_params = search_params.to_h
@q = domains.search(params[:q]) new_search_params[:name_matches] = "%#{new_search_params[:name_matches]}%"
@q = domains.search(new_search_params)
@domains = @q.result.page(params[:page]) @domains = @q.result.page(params[:page])
params[:q][:name_matches] = n_cache # we don't want to show wildcards in search form
end end
end end
@ -47,9 +48,10 @@ class Registrar
domain_presenters << ::DomainPresenter.new(domain: domain, view: view_context) domain_presenters << ::DomainPresenter.new(domain: domain, view: view_context)
end end
csv = Registrar::DomainListCSVPresenter.new(domains: domain_presenters, view: view_context).to_s raw_csv = Registrar::DomainListCSVPresenter.new(domains: domain_presenters,
view: view_context).to_s
filename = "Domains_#{l(Time.zone.now, format: :filename)}.csv" filename = "Domains_#{l(Time.zone.now, format: :filename)}.csv"
send_data(csv, filename: filename) send_data raw_csv, filename: filename, type: "#{Mime[:csv]}; charset=utf-8"
end end
end end
end end
@ -57,6 +59,7 @@ class Registrar
def info def info
authorize! :info, Depp::Domain authorize! :info, Depp::Domain
@data = @domain.info(params[:domain_name]) if params[:domain_name] @data = @domain.info(params[:domain_name]) if params[:domain_name]
@client_holded = client_holded(@data)
if response_ok? if response_ok?
render 'info' render 'info'
else else
@ -83,7 +86,7 @@ class Registrar
def create def create
authorize! :create, Depp::Domain authorize! :create, Depp::Domain
@domain_params = params[:domain] @domain_params = domain_params.to_h
@data = @domain.create(@domain_params) @data = @domain.create(@domain_params)
if response_ok? if response_ok?
@ -97,12 +100,14 @@ class Registrar
authorize! :update, Depp::Domain authorize! :update, Depp::Domain
@data = @domain.info(params[:domain_name]) @data = @domain.info(params[:domain_name])
@domain_params = Depp::Domain.construct_params_from_server_data(@data) @domain_params = Depp::Domain.construct_params_from_server_data(@data)
@dispute = Dispute.active.find_by(domain_name: params[:domain_name])
end end
def update def update
authorize! :update, Depp::Domain authorize! :update, Depp::Domain
@domain_params = params[:domain] @domain_params = params[:domain]
@data = @domain.update(@domain_params) @data = @domain.update(@domain_params)
@dispute = Dispute.active.find_by(domain_name: @domain_params[:name])
if response_ok? if response_ok?
redirect_to info_registrar_domains_url(domain_name: @domain_params[:name]) redirect_to info_registrar_domains_url(domain_name: @domain_params[:name])
@ -151,29 +156,60 @@ class Registrar
render json: scope.pluck(:name, :code).map { |c| { display_key: "#{c.second} #{c.first}", value: c.second } } render json: scope.pluck(:name, :code).map { |c| { display_key: "#{c.second} #{c.first}", value: c.second } }
end 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 private
def init_domain def init_domain
@domain = Depp::Domain.new(current_user: depp_current_user) @domain = Depp::Domain.new(current_user: depp_current_user)
end end
def client_holded(data)
data.css('status')&.map { |element| element.attribute('s').value }
&.any? { |status| status == DomainStatus::CLIENT_HOLD }
end
def contacts def contacts
current_registrar_user.registrar.contacts current_registrar_user.registrar.contacts
end end
def normalize_search_parameters def normalize_search_parameters
ca_cache = params[:q][:valid_to_lteq] ca_cache = search_params[:valid_to_lteq]
begin begin
end_time = params[:q][:valid_to_lteq].try(:to_date) end_time = search_params[:valid_to_lteq].try(:to_date)
params[:q][:valid_to_lteq] = end_time.try(:end_of_day) search_params[:valid_to_lteq] = end_time.try(:end_of_day)
rescue rescue
logger.warn('Invalid date') logger.warn('Invalid date')
end end
yield yield
params[:q][:valid_to_lteq] = ca_cache 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 end
end end

View file

@ -1,20 +0,0 @@
class Registrar
class KeyrelaysController < DeppController
def show
authorize! :view, Depp::Keyrelay
end
def create
authorize! :create, Depp::Keyrelay
keyrelay = Depp::Keyrelay.new(current_user: depp_current_user)
@data = keyrelay.keyrelay(params)
if response_ok?
flash[:epp_results] = [{ 'code' => '1000', 'msg' => 'Command completed successfully', 'show' => true }]
redirect_to registrar_keyrelay_path
else
render 'show'
end
end
end
end

View file

@ -5,48 +5,51 @@ class Registrar
skip_authorization_check # actually anyone can pay, no problems at all skip_authorization_check # actually anyone can pay, no problems at all
skip_before_action :authenticate_registrar_user!, :check_ip_restriction, skip_before_action :authenticate_registrar_user!, :check_ip_restriction,
only: [:back, :callback] only: [:back, :callback]
before_action :check_supported_payment_method
before_action :check_supported_payment_method, only: [:pay]
def pay def pay
invoice = Invoice.find(params[:invoice_id]) invoice = Invoice.find(params[:invoice_id])
bank = params[:bank] channel = params[:bank]
opts = {
return_url: registrar_return_payment_with_url( @payment_order = PaymentOrder.new_with_type(type: channel, invoice: invoice)
bank, invoice_id: invoice @payment_order.save
), @payment_order.reload
response_url: registrar_response_payment_with_url(
bank, invoice_id: invoice @payment_order.return_url = registrar_return_payment_with_url(@payment_order)
) @payment_order.response_url = registrar_response_payment_with_url(@payment_order)
}
@payment = ::PaymentOrders.create_with_type(bank, invoice, opts) @payment_order.save
@payment.create_transaction @payment_order.reload
end end
def back def back
invoice = Invoice.find(params[:invoice_id]) @payment_order = PaymentOrder.find_by!(id: params[:payment_order])
opts = { response: params } @payment_order.update!(response: params.to_unsafe_h)
@payment = ::PaymentOrders.create_with_type(params[:bank], invoice, opts)
if @payment.valid_response_from_intermediary? && @payment.settled_payment?
@payment.complete_transaction
if invoice.paid? if @payment_order.payment_received?
flash[:notice] = t(:pending_applied) @payment_order.complete_transaction
if @payment_order.invoice.paid?
flash[:notice] = t('.payment_successful')
else else
flash[:alert] = t(:something_wrong) flash[:alert] = t('.successful_payment_backend_error')
end end
else else
flash[:alert] = t(:something_wrong) @payment_order.create_failure_report
flash[:alert] = t('.payment_not_received')
end end
redirect_to registrar_invoice_path(invoice) redirect_to registrar_invoice_path(@payment_order.invoice)
end end
def callback def callback
invoice = Invoice.find(params[:invoice_id]) @payment_order = PaymentOrder.find_by!(id: params[:payment_order])
opts = { response: params } @payment_order.update!(response: params.to_unsafe_h)
@payment = ::PaymentOrders.create_with_type(params[:bank], invoice, opts)
if @payment.valid_response_from_intermediary? && @payment.settled_payment? if @payment_order.payment_received?
@payment.complete_transaction @payment_order.complete_transaction
else
@payment_order.create_failure_report
end end
render status: 200, json: { status: 'ok' } render status: 200, json: { status: 'ok' }
@ -55,13 +58,9 @@ class Registrar
private private
def check_supported_payment_method def check_supported_payment_method
return if supported_payment_method? return if PaymentOrder.supported_method?(params[:bank], shortname: true)
raise StandardError.new("Not supported payment method")
end
raise(StandardError, 'Not supported payment method')
def supported_payment_method?
PaymentOrders::PAYMENT_METHODS.include?(params[:bank])
end end
end end
end end

View file

@ -26,21 +26,6 @@ class Registrar
render 'show' render 'show'
end end
# TODO: Keyrelay is disabled for now
# def confirm_keyrelay
# authorize! :confirm, :keyrelay
# domain_params = params[:domain]
# @data = @domain.confirm_keyrelay(domain_params)
# if response_ok?
# redirect_to info_registrar_domains_url(domain_name: domain_params[:name])
# else
# @results = @data.css('result')
# @data = depp_current_user.request(@ex.poll)
# render 'show'
# end
# end
def confirm_transfer def confirm_transfer
domain_params = params[:domain] domain_params = params[:domain]
@data = @domain.confirm_transfer(domain_params) @data = @domain.confirm_transfer(domain_params)

View file

@ -31,7 +31,8 @@ class Registrar
end end
if @depp_user.pki if @depp_user.pki
unless @api_user.registrar_pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'], request.env['HTTP_SSL_CLIENT_S_DN_CN']) unless @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) @depp_user.errors.add(:base, :invalid_cert)
end end
end end
@ -55,7 +56,7 @@ class Registrar
ip_allowed = restricted_ip.can_access_registrar_area?(resource.registrar) ip_allowed = restricted_ip.can_access_registrar_area?(resource.registrar)
unless ip_allowed unless ip_allowed
render text: t('registrar.authorization.ip_not_allowed', ip: request.ip) render plain: t('registrar.authorization.ip_not_allowed', ip: request.ip)
warden.logout(:registrar_user) warden.logout(:registrar_user)
return return
end end
@ -171,7 +172,7 @@ class Registrar
return if allowed return if allowed
render text: t('registrar.authorization.ip_not_allowed', ip: request.ip) render plain: t('registrar.authorization.ip_not_allowed', ip: request.ip)
end end
def current_ability def current_ability

View file

@ -19,7 +19,7 @@ class Registrar
xml_dir_path = Rails.root + 'app/views/registrar/xml_consoles/epp_requests' xml_dir_path = Rails.root + 'app/views/registrar/xml_consoles/epp_requests'
xml = File.read("#{xml_dir_path}/#{params[:obj]}/#{params[:epp_action]}.xml") xml = File.read("#{xml_dir_path}/#{params[:obj]}/#{params[:epp_action]}.xml")
xml.gsub!('<clTRID>ABC-12345</clTRID>', "<clTRID>#{cl_trid}</clTRID>") xml.gsub!('<clTRID>ABC-12345</clTRID>', "<clTRID>#{cl_trid}</clTRID>")
render text: xml render plain: xml
end end
end end
end end

View file

@ -0,0 +1,23 @@
module Repp
module V1
class AuctionsController < ActionController::API
def index
auctions = Auction.started
render json: { count: auctions.count,
auctions: auctions_to_json(auctions) }
end
private
def auctions_to_json(auctions)
auctions.map do |e|
{
domain_name: e.domain,
punycode_domain_name: SimpleIDN.to_ascii(e.domain),
}
end
end
end
end
end

View file

@ -0,0 +1,15 @@
module Repp
module V1
class RetainedDomainsController < ActionController::API
def index
domains = RetainedDomains.new(query_params)
render json: { count: domains.count, domains: domains.to_jsonable }
end
def query_params
params.permit(:type)
end
end
end
end

View file

@ -33,6 +33,18 @@ module ApplicationHelper
end end
end end
def current_commit_link
hash = `git rev-parse --short HEAD`
current_repo = `git remote get-url origin`.gsub('com:', 'com/')
.gsub('git@', 'https://')
.gsub('.git', '')
link_to hash.to_s, "#{current_repo}/commit/#{hash}",
class: 'footer-version-link',
target: '_blank',
rel: 'noopener'
end
def creator_link(model) def creator_link(model)
return 'not present' if model.blank? return 'not present' if model.blank?
return 'unknown' if model.creator.blank? return 'unknown' if model.creator.blank?
@ -96,4 +108,14 @@ module ApplicationHelper
def body_css_class def body_css_class
[controller_path.split('/').map!(&:dasherize), action_name.dasherize, 'page'].join('-') [controller_path.split('/').map!(&:dasherize), action_name.dasherize, 'page'].join('-')
end end
def verified_email_span(verification)
content_tag(:span, verification.email, class: verified_email_class(verification))
end
def verified_email_class(verification)
return 'text-danger' if verification.failed?
return 'text-primary' if verification.not_verified?
return 'text-success' if verification.verified?
end
end end

View file

@ -0,0 +1,125 @@
class DirectoInvoiceForwardJob < Que::Job
def run(monthly: false, dry: false)
@dry = dry
(@month = Time.zone.now - 1.month) if monthly
api_url = ENV['directo_invoice_url']
sales_agent = Setting.directo_sales_agent
payment_term = Setting.directo_receipt_payment_term
@prepayment_product_id = Setting.directo_receipt_product_name
@client = DirectoApi::Client.new(api_url, sales_agent, payment_term)
monthly ? send_monthly_invoices : send_receipts
end
def send_receipts
unsent_invoices = Invoice.where(in_directo: false).non_cancelled
Rails.logger.info("[DIRECTO] Trying to send #{unsent_invoices.count} prepayment invoices")
unsent_invoices.each do |invoice|
unless valid_invoice_conditions?(invoice)
Rails.logger.info "[DIRECTO] Invoice #{invoice.number} has been skipped"
next
end
@client.invoices.add_with_schema(invoice: invoice.as_directo_json, schema: 'prepayment')
end
sync_with_directo
end
def send_monthly_invoices
Registrar.where.not(test_registrar: true).find_each do |registrar|
fetch_monthly_summary(registrar: registrar)
end
return unless @client.invoices.count.positive?
sync_with_directo
end
def fetch_monthly_summary(registrar:)
return unless registrar.cash_account
summary = registrar.monthly_summary(month: @month)
@client.invoices.add_with_schema(invoice: summary, schema: 'summary') unless summary.nil?
end
def assign_monthly_numbers
if directo_counter_exceedable?(@client.invoices.count)
raise 'Directo Counter is going to be out of period!'
end
min_directo = Setting.directo_monthly_number_min.presence.try(:to_i)
directo_number = [Setting.directo_monthly_number_last.presence.try(:to_i),
min_directo].compact.max || 0
@client.invoices.each do |inv|
directo_number += 1
inv.number = directo_number
end
end
def valid_invoice_conditions?(invoice)
if invoice.account_activity.nil? || invoice.account_activity.bank_transaction.nil? ||
invoice.account_activity.bank_transaction.sum.nil? ||
invoice.account_activity.bank_transaction.sum != invoice.total
return false
end
true
end
def sync_with_directo
assign_monthly_numbers if @month
Rails.logger.info("[Directo] - attempting to send following XML:\n #{@client.invoices.as_xml}")
return if @dry
res = @client.invoices.deliver(ssl_verify: false)
process_directo_response(res.body, @client.invoices.as_xml)
rescue SocketError, Errno::ECONNREFUSED, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
Rails.logger.info('[Directo] Failed to communicate via API')
end
def process_directo_response(xml, req)
Rails.logger.info "[Directo] - Responded with body: #{xml}"
Nokogiri::XML(xml).css('Result').each do |res|
if @month
mark_invoice_as_sent(res: res, req: req)
else
inv = Invoice.find_by(number: res.attributes['docid'].value.to_i)
mark_invoice_as_sent(invoice: inv, res: res, req: req)
end
end
end
def mark_invoice_as_sent(invoice: nil, res:, req:)
directo_record = Directo.new(response: res.as_json.to_h,
request: req, invoice_number: res.attributes['docid'].value.to_i)
if invoice
directo_record.item = invoice
invoice.update(in_directo: true)
else
update_directo_number(num: directo_record.invoice_number)
end
directo_record.save!
end
def update_directo_number(num:)
return unless num.to_i > Setting.directo_monthly_number_last.to_i
Setting.directo_monthly_number_last = num.to_i
end
def directo_counter_exceedable?(invoice_count)
min_directo = Setting.directo_monthly_number_min.presence.try(:to_i)
max_directo = Setting.directo_monthly_number_max.presence.try(:to_i)
last_directo = [Setting.directo_monthly_number_last.presence.try(:to_i),
min_directo].compact.max || 0
return true if max_directo && max_directo < (last_directo + invoice_count)
false
end
end

View file

@ -0,0 +1,63 @@
class DisputeStatusUpdateJob < Que::Job
def run(logger: Logger.new(STDOUT))
@logger = logger
@backlog = { 'activated': 0, 'closed': 0, 'activate_fail': [], 'close_fail': [] }
.with_indifferent_access
close_disputes
activate_disputes
@logger.info "DisputeStatusUpdateJob - All done. Closed #{@backlog['closed']} and " \
"activated #{@backlog['activated']} disputes."
show_failed_disputes unless @backlog['activate_fail'].empty? && @backlog['close_fail'].empty?
end
def close_disputes
disputes = Dispute.where(closed: nil).where('expires_at < ?', Time.zone.today).all
@logger.info "DisputeStatusUpdateJob - Found #{disputes.count} closable disputes"
disputes.each do |dispute|
process_dispute(dispute, closing: true)
end
end
def activate_disputes
disputes = Dispute.where(closed: nil, starts_at: Time.zone.today).all
@logger.info "DisputeStatusUpdateJob - Found #{disputes.count} activatable disputes"
disputes.each do |dispute|
process_dispute(dispute, closing: false)
end
end
def process_dispute(dispute, closing: false)
intent = closing ? 'close' : 'activate'
success = closing ? dispute.close(initiator: 'Job') : dispute.generate_data
create_backlog_entry(dispute: dispute, intent: intent, successful: success)
end
def create_backlog_entry(dispute:, intent:, successful:)
if successful
@backlog["#{intent}d"] += 1
@logger.info "DisputeStatusUpdateJob - #{intent}d dispute " \
" for '#{dispute.domain_name}'"
else
@backlog["#{intent}_fail"] << dispute.id
@logger.info 'DisputeStatusUpdateJob - Failed to' \
"#{intent} dispute for '#{dispute.domain_name}'"
end
end
def show_failed_disputes
if @backlog['close_fail'].any?
@logger.info('DisputeStatusUpdateJob - Failed to close disputes with Ids:' \
"#{@backlog['close_fail']}")
end
return unless @backlog['activate_fail'].any?
@logger.info('DisputeStatusUpdateJob - Failed to activate disputes with Ids:' \
"#{@backlog['activate_fail']}")
end
end

View file

@ -1,6 +1,6 @@
class DomainDeleteConfirmJob < Que::Job class DomainDeleteConfirmJob < Que::Job
def run(domain_id, action, initiator = nil) def run(domain_id, action, initiator = nil)
::PaperTrail.whodunnit = "job - #{self.class.name} - #{action} by #{initiator}" ::PaperTrail.request.whodunnit = "job - #{self.class.name} - #{action} by #{initiator}"
# it's recommended to keep transaction against job table as short as possible. # it's recommended to keep transaction against job table as short as possible.
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
domain = Epp::Domain.find(domain_id) domain = Epp::Domain.find(domain_id)

View file

@ -3,7 +3,7 @@ class DomainDeleteJob < Que::Job
def run(domain_id) def run(domain_id)
domain = Domain.find(domain_id) domain = Domain.find(domain_id)
::PaperTrail.whodunnit = "job - #{self.class.name}" ::PaperTrail.request.whodunnit = "job - #{self.class.name}"
WhoisRecord.where(domain_id: domain.id).destroy_all WhoisRecord.where(domain_id: domain.id).destroy_all
domain.destroy domain.destroy

View file

@ -1,6 +1,6 @@
class DomainUpdateConfirmJob < Que::Job class DomainUpdateConfirmJob < Que::Job
def run(domain_id, action, initiator = nil) def run(domain_id, action, initiator = nil)
::PaperTrail.whodunnit = "job - #{self.class.name} - #{action} by #{initiator}" ::PaperTrail.request.whodunnit = "job - #{self.class.name} - #{action} by #{initiator}"
# it's recommended to keep transaction against job table as short as possible. # it's recommended to keep transaction against job table as short as possible.
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
domain = Epp::Domain.find(domain_id) domain = Epp::Domain.find(domain_id)

View file

@ -0,0 +1,11 @@
class RegenerateSubzoneWhoisesJob < Que::Job
def run
subzones = DNS::Zone.all
subzones.each do |zone|
next unless zone.subzone?
UpdateWhoisRecordJob.enqueue zone.origin, 'zone'
end
end
end

View file

@ -0,0 +1,43 @@
class SendEInvoiceJob < Que::Job
def run(invoice_id)
invoice = run_condition(Invoice.find_by(id: invoice_id))
invoice.to_e_invoice.deliver
ActiveRecord::Base.transaction do
invoice.update(e_invoice_sent_at: Time.zone.now)
log_success(invoice)
destroy
end
rescue StandardError => e
log_error(invoice: invoice, error: e)
raise e
end
private
def run_condition(invoice)
destroy unless invoice
destroy if invoice.do_not_send_e_invoice?
invoice
end
def log_success(invoice)
id = invoice.try(:id) || invoice
message = "E-Invoice for an invoice with ID # #{id} was sent successfully"
logger.info message
end
def log_error(invoice:, error:)
id = invoice.try(:id) || invoice
message = <<~TEXT.squish
There was an error sending e-invoice for invoice with ID # #{id}.
The error message was the following: #{error}
This job will retry.
TEXT
logger.error message
end
def logger
Rails.logger
end
end

View file

@ -1,16 +1,12 @@
class UpdateWhoisRecordJob < Que::Job class UpdateWhoisRecordJob < Que::Job
def run(names, type) def run(names, type)
::PaperTrail.whodunnit = "job - #{self.class.name} - #{type}" ::PaperTrail.request.whodunnit = "job - #{self.class.name} - #{type}"
klass = case type klass = determine_class(type)
when 'reserved'then ReservedDomain
when 'blocked' then BlockedDomain
when 'domain' then Domain
end
Array(names).each do |name| Array(names).each do |name|
record = klass.find_by(name: name) record = find_record(klass, name)
if record if record
send "update_#{type}", record send "update_#{type}", record
else else
@ -19,7 +15,19 @@ class UpdateWhoisRecordJob < Que::Job
end end
end end
def find_record(klass, name)
klass == DNS::Zone ? klass.find_by(origin: name) : klass.find_by(name: name)
end
def determine_class(type)
case type
when 'reserved' then ReservedDomain
when 'blocked' then BlockedDomain
when 'domain' then Domain
when 'disputed' then Dispute.active
when 'zone' then DNS::Zone
end
end
def update_domain(domain) def update_domain(domain)
domain.whois_record ? domain.whois_record.save : domain.create_whois_record domain.whois_record ? domain.whois_record.save : domain.create_whois_record
@ -33,6 +41,13 @@ class UpdateWhoisRecordJob < Que::Job
update_reserved(record) update_reserved(record)
end end
def update_disputed(record)
update_reserved(record)
end
def update_zone(record)
update_reserved(record)
end
# 1. deleting own # 1. deleting own
# 2. trying to regenerate reserved in order domain is still in the list # 2. trying to regenerate reserved in order domain is still in the list
@ -41,14 +56,32 @@ class UpdateWhoisRecordJob < Que::Job
BlockedDomain.find_by(name: name).try(:generate_data) BlockedDomain.find_by(name: name).try(:generate_data)
ReservedDomain.find_by(name: name).try(:generate_data) ReservedDomain.find_by(name: name).try(:generate_data)
Dispute.active.find_by(domain_name: name).try(:generate_data)
end end
def delete_reserved(name) def delete_reserved(name)
Domain.where(name: name).any? remove_status_from_whois(domain_name: name, domain_status: 'Reserved')
Whois::Record.where(name: name).delete_all
end end
def delete_blocked(name) def delete_blocked(name)
delete_reserved(name) delete_reserved(name)
end end
def delete_disputed(name)
return if Dispute.active.find_by(domain_name: name).present?
remove_status_from_whois(domain_name: name, domain_status: 'disputed')
end
def delete_zone(name)
WhoisRecord.where(name: name).destroy_all
Whois::Record.where(name: name).destroy_all
end
def remove_status_from_whois(domain_name:, domain_status:)
Whois::Record.where(name: domain_name).each do |r|
r.json['status'] = r.json['status'].delete_if { |status| status == domain_status }
r.json['status'].blank? ? r.destroy : r.save
end
end
end end

View file

@ -0,0 +1,45 @@
class VerifyEmailsJob < Que::Job
def run(verification_id)
email_address_verification = run_condition(EmailAddressVerification.find(verification_id))
return if email_address_verification.recently_verified?
ActiveRecord::Base.transaction do
email_address_verification.verify
log_success(email_address_verification)
destroy
end
rescue StandardError => e
log_error(verification: email_address_verification, error: e)
raise e
end
private
def run_condition(email_address_verification)
destroy unless email_address_verification
destroy if email_address_verification.recently_verified?
email_address_verification
end
def logger
@logger ||= Logger.new(Rails.root.join('log', 'email_verification.log'))
end
def log_success(verification)
email = verification.try(:email) || verification
message = "Email address #{email} verification done"
logger.info message
end
def log_error(verification:, error:)
email = verification.try(:email) || verification
message = <<~TEXT.squish
There was an error verifying email #{email}.
The error message was the following: #{error}
This job will retry.
TEXT
logger.error message
end
end

View file

@ -39,10 +39,12 @@ class DomainDeleteMailer < ApplicationMailer
@registrant = RegistrantPresenter.new(registrant: registrant, view: view_context) @registrant = RegistrantPresenter.new(registrant: registrant, view: view_context)
@redemption_grace_period = Setting.redemption_grace_period @redemption_grace_period = Setting.redemption_grace_period
@expire_warning_period = Setting.expire_warning_period
@delete_period_length = @redemption_grace_period + @expire_warning_period
subject = default_i18n_subject(domain_name: domain.name) subject = default_i18n_subject(domain_name: domain.name)
mail(from: forced_email_from, mail(from: forced_email_from,
to: domain.primary_contact_emails, to: domain.force_delete_contact_emails,
subject: subject, subject: subject,
template_path: 'mailers/domain_delete_mailer/forced', template_path: 'mailers/domain_delete_mailer/forced',
template_name: template_name) template_name: template_name)

View file

@ -34,8 +34,6 @@ class Ability
if @user.registrar.api_ip_white?(@ip) if @user.registrar.api_ip_white?(@ip)
can :manage, :poll can :manage, :poll
can :manage, Depp::Contact can :manage, Depp::Contact
# can :manage, Depp::Keyrelay # TODO: Keyrelay is disabled for now
# can :confirm, :keyrelay # TODO: Keyrelay is disabled for now
can :manage, :xml_console can :manage, :xml_console
can :manage, Depp::Domain can :manage, Depp::Domain
end end
@ -48,13 +46,13 @@ class Ability
# can(:create, :epp_request) # can(:create, :epp_request)
# Epp::Domain # Epp::Domain
can(:info, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || pw.blank? ? true : d.transfer_code == pw } can(:info, Epp::Domain)
can(:check, Epp::Domain) can(:check, Epp::Domain)
can(:create, Epp::Domain) can(:create, Epp::Domain)
can(:renew, Epp::Domain) { |d| d.registrar_id == @user.registrar_id } can(:renew, Epp::Domain) { |d| d.registrar_id == @user.registrar_id }
can(:remove_hold, Epp::Domain) { |d| d.registrar_id == @user.registrar_id }
can(:update, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw } can(:update, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw }
can(:transfer, Epp::Domain) { |d, pw| d.transfer_code == pw } can(:transfer, Epp::Domain)
can(:view_password, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw }
can(:delete, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw } can(:delete, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw }
# Epp::Contact # Epp::Contact
@ -65,6 +63,7 @@ class Ability
can(:update, Epp::Contact) { |c, pw| c.registrar_id == @user.registrar_id || c.auth_info == pw } can(:update, Epp::Contact) { |c, pw| c.registrar_id == @user.registrar_id || c.auth_info == pw }
can(:delete, Epp::Contact) { |c, pw| c.registrar_id == @user.registrar_id || c.auth_info == pw } can(:delete, Epp::Contact) { |c, pw| c.registrar_id == @user.registrar_id || c.auth_info == pw }
can(:renew, Epp::Contact) can(:renew, Epp::Contact)
can(:transfer, Epp::Contact)
can(:view_password, Epp::Contact) { |c, pw| c.registrar_id == @user.registrar_id || c.auth_info == pw } can(:view_password, Epp::Contact) { |c, pw| c.registrar_id == @user.registrar_id || c.auth_info == pw }
end end
@ -95,13 +94,13 @@ class Ability
can :manage, ApiUser can :manage, ApiUser
can :manage, AdminUser can :manage, AdminUser
can :manage, Certificate can :manage, Certificate
can :manage, Keyrelay
can :manage, LegalDocument can :manage, LegalDocument
can :manage, BankStatement can :manage, BankStatement
can :manage, BankTransaction can :manage, BankTransaction
can :manage, Invoice can :manage, Invoice
can :manage, WhiteIp can :manage, WhiteIp
can :manage, AccountActivity can :manage, AccountActivity
can :manage, Dispute
can :read, ApiLog::EppLog can :read, ApiLog::EppLog
can :read, ApiLog::ReppLog can :read, ApiLog::ReppLog
can :update, :pending can :update, :pending

View file

@ -1,4 +1,4 @@
class Account < ActiveRecord::Base class Account < ApplicationRecord
include Versions include Versions
belongs_to :registrar, required: true belongs_to :registrar, required: true

View file

@ -1,4 +1,4 @@
class AccountActivity < ActiveRecord::Base class AccountActivity < ApplicationRecord
include Versions include Versions
belongs_to :account, required: true belongs_to :account, required: true
belongs_to :bank_transaction belongs_to :bank_transaction

View file

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

View file

@ -0,0 +1,105 @@
module Actions
class ContactUpdate
attr_reader :contact
attr_reader :new_attributes
attr_reader :legal_document
attr_reader :ident
attr_reader :user
def initialize(contact, new_attributes, legal_document, ident, user)
@contact = contact
@new_attributes = new_attributes
@legal_document = legal_document
@ident = ident
@user = user
end
def call
maybe_remove_address
maybe_update_statuses
maybe_update_ident
maybe_attach_legal_doc
commit
end
def maybe_remove_address
return if Contact.address_processing?
new_attributes.delete(:city)
new_attributes.delete(:zip)
new_attributes.delete(:street)
new_attributes.delete(:state)
new_attributes.delete(:country_code)
end
def maybe_update_statuses
return unless Setting.client_status_editing_enabled
new_statuses =
contact.statuses - new_attributes[:statuses_to_remove] + new_attributes[:statuses_to_add]
new_attributes[:statuses] = new_statuses
end
def maybe_attach_legal_doc
return unless legal_document
document = contact.legal_documents.create(
document_type: legal_document[:type],
body: legal_document[:body]
)
contact.legal_document_id = document.id
end
def maybe_update_ident
return unless ident[:ident]
if contact.identifier.valid?
submitted_ident = ::Contact::Ident.new(code: ident[:ident],
type: ident[:ident_type],
country_code: ident[:ident_country_code])
if submitted_ident != contact.identifier
contact.add_epp_error('2308', nil, nil, I18n.t('epp.contacts.errors.valid_ident'))
@error = true
end
else
ident_update_attempt = ident[:ident] != contact.ident
if ident_update_attempt
contact.add_epp_error('2308', nil, nil, I18n.t('epp.contacts.errors.ident_update'))
@error = true
end
identifier = ::Contact::Ident.new(code: ident[:ident],
type: ident[:ident_type],
country_code: ident[:ident_country_code])
identifier.validate
contact.identifier = identifier
contact.ident_updated_at ||= Time.zone.now
end
end
def commit
return false if @error
contact.upid = user.registrar&.id
contact.up_date = Time.zone.now
contact.attributes = new_attributes
email_changed = contact.will_save_change_to_email?
old_email = contact.email_was
updated = contact.save
if updated && email_changed && contact.registrant?
ContactMailer.email_changed(contact: contact, old_email: old_email).deliver_now
end
updated
end
end
end

View file

@ -4,7 +4,7 @@ class AdminUser < User
validates :identity_code, presence: true, if: -> { country_code == 'EE' } validates :identity_code, presence: true, if: -> { country_code == 'EE' }
validates :email, presence: true validates :email, presence: true
validates :password, :password_confirmation, presence: true, if: :new_record? validates :password, :password_confirmation, presence: true, if: :new_record?
validates :password_confirmation, presence: true, if: :encrypted_password_changed? validates :password_confirmation, presence: true, if: :will_save_change_to_encrypted_password?
validate :validate_identity_code, if: -> { country_code == 'EE' } validate :validate_identity_code, if: -> { country_code == 'EE' }
ROLES = %w(user customer_service admin) # should not match to api_users roles ROLES = %w(user customer_service admin) # should not match to api_users roles

View file

@ -1,5 +1,5 @@
module ApiLog module ApiLog
class Db < ActiveRecord::Base class Db < ApplicationRecord
self.abstract_class = true self.abstract_class = true
# to_sym is needed because passing a string to ActiveRecord::Base.establish_connection # to_sym is needed because passing a string to ActiveRecord::Base.establish_connection
# for a configuration lookup is deprecated # for a configuration lookup is deprecated

View file

@ -26,9 +26,9 @@ class ApiUser < User
validates :username, uniqueness: true validates :username, uniqueness: true
delegate :code, :name, to: :registrar, prefix: true delegate :code, :name, to: :registrar, prefix: true
delegate :legaldoc_mandatory?, to: :registrar
alias_attribute :login, :username alias_attribute :login, :username
attr_accessor :registrar_typeahead
SUPER = 'super' SUPER = 'super'
EPP = 'epp' EPP = 'epp'
@ -44,7 +44,7 @@ class ApiUser < User
after_initialize :set_defaults after_initialize :set_defaults
def set_defaults def set_defaults
return unless new_record? return unless new_record?
self.active = true unless active_changed? self.active = true unless saved_change_to_active?
end end
class << self class << self
@ -53,10 +53,6 @@ class ApiUser < User
end end
end end
def registrar_typeahead
@registrar_typeahead || registrar || nil
end
def to_s def to_s
username username
end end
@ -69,24 +65,14 @@ class ApiUser < User
registrar.notifications.unread registrar.notifications.unread
end end
def registrar_pki_ok?(crt, cn) def pki_ok?(crt, com, api: true)
return false if crt.blank? || cn.blank? return false if crt.blank? || com.blank?
crt = crt.split(' ').join("\n")
crt.gsub!("-----BEGIN\nCERTIFICATE-----\n", "-----BEGIN CERTIFICATE-----\n")
crt.gsub!("\n-----END\nCERTIFICATE-----", "\n-----END CERTIFICATE-----")
cert = OpenSSL::X509::Certificate.new(crt)
md5 = OpenSSL::Digest::MD5.new(cert.to_der).to_s
certificates.registrar.exists?(md5: md5, common_name: cn)
end
def api_pki_ok?(crt, cn) origin = api ? certificates.api : certificates.registrar
return false if crt.blank? || cn.blank? cert = machine_readable_certificate(crt)
crt = crt.split(' ').join("\n")
crt.gsub!("-----BEGIN\nCERTIFICATE-----\n", "-----BEGIN CERTIFICATE-----\n")
crt.gsub!("\n-----END\nCERTIFICATE-----", "\n-----END CERTIFICATE-----")
cert = OpenSSL::X509::Certificate.new(crt)
md5 = OpenSSL::Digest::MD5.new(cert.to_der).to_s md5 = OpenSSL::Digest::MD5.new(cert.to_der).to_s
certificates.api.exists?(md5: md5, common_name: cn)
origin.exists?(md5: md5, common_name: com, revoked: false)
end end
def linked_users def linked_users
@ -98,4 +84,14 @@ class ApiUser < User
def linked_with?(another_api_user) def linked_with?(another_api_user)
another_api_user.identity_code == self.identity_code another_api_user.identity_code == self.identity_code
end end
private
def machine_readable_certificate(cert)
cert = cert.split(' ').join("\n")
cert.gsub!("-----BEGIN\nCERTIFICATE-----\n", "-----BEGIN CERTIFICATE-----\n")
cert.gsub!("\n-----END\nCERTIFICATE-----", "\n-----END CERTIFICATE-----")
OpenSSL::X509::Certificate.new(cert)
end
end end

View file

@ -0,0 +1,3 @@
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end

View file

@ -1,4 +1,4 @@
class Auction < ActiveRecord::Base class Auction < ApplicationRecord
enum status: { enum status: {
started: 'started', started: 'started',
awaiting_payment: 'awaiting_payment', awaiting_payment: 'awaiting_payment',
@ -23,10 +23,19 @@ class Auction < ActiveRecord::Base
save! save!
end end
def whois_deadline
registration_deadline.try(:to_s, :iso8601)
end
def mark_as_no_bids def mark_as_no_bids
no_bids! no_bids!
end end
def mark_deadline(registration_deadline)
self.registration_deadline = registration_deadline
save!
end
def mark_as_payment_received def mark_as_payment_received
self.status = self.class.statuses[:payment_received] self.status = self.class.statuses[:payment_received]
generate_registration_code generate_registration_code

View file

@ -1,4 +1,4 @@
class BankStatement < ActiveRecord::Base class BankStatement < ApplicationRecord
include Versions include Versions
has_many :bank_transactions has_many :bank_transactions
@ -25,10 +25,16 @@ class BankStatement < ActiveRecord::Base
bank_transactions.build(bt_params) bank_transactions.build(bt_params)
end end
prepare_dir
self.import_file_path = "#{ENV['bank_statement_import_dir']}/#{Time.zone.now.to_formatted_s(:number)}.txt" self.import_file_path = "#{ENV['bank_statement_import_dir']}/#{Time.zone.now.to_formatted_s(:number)}.txt"
File.open(import_file_path, 'w') { |f| f.write(th6_file.open.read) } File.open(import_file_path, 'w') { |f| f.write(th6_file.open.read) }
end end
def prepare_dir
dirname = ENV['bank_statement_import_dir']
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
end
def parse_th6_row(row) def parse_th6_row(row)
return parse_th6_header(row) if row[4, 3].strip == '000' return parse_th6_header(row) if row[4, 3].strip == '000'
return if row[4, 3].strip == '999' # skip footer return if row[4, 3].strip == '999' # skip footer
@ -45,7 +51,7 @@ class BankStatement < ActiveRecord::Base
buyer_name: row[83, 35].strip, buyer_name: row[83, 35].strip,
document_no: row[118, 8].strip, document_no: row[118, 8].strip,
description: row[126, 140].strip, description: row[126, 140].strip,
sum: BigDecimal.new(row[268, 12].strip) / BigDecimal.new('100.0'), sum: BigDecimal(row[268, 12].strip) / BigDecimal('100.0'),
reference_no: row[280, 35].strip reference_no: row[280, 35].strip
} }
end end
@ -80,7 +86,9 @@ class BankStatement < ActiveRecord::Base
status == FULLY_BINDED status == FULLY_BINDED
end end
def bind_invoices def bind_invoices(manual: false)
bank_transactions.unbinded.each(&:autobind_invoice) bank_transactions.unbinded.each do |transaction|
transaction.autobind_invoice(manual: manual)
end
end end
end end

View file

@ -1,4 +1,4 @@
class BankTransaction < ActiveRecord::Base class BankTransaction < ApplicationRecord
include Versions include Versions
belongs_to :bank_statement belongs_to :bank_statement
has_one :account_activity has_one :account_activity
@ -13,53 +13,72 @@ class BankTransaction < ActiveRecord::Base
def binded_invoice def binded_invoice
return unless binded? return unless binded?
account_activity.invoice account_activity.invoice
end end
def invoice_num
return @invoice_no if defined?(@invoice_no)
match = description.match(/^[^\d]*(\d+)/)
return unless match
@invoice_no = match[1].try(:to_i)
end
def invoice def invoice
@invoice ||= registrar.invoices.find_by(number: invoice_num) if registrar return unless registrar
@invoice ||= registrar.invoices
.order(created_at: :asc)
.unpaid
.non_cancelled
.find_by(total: sum)
end end
def registrar def registrar
@registrar ||= Invoice.find_by(reference_no: reference_no)&.buyer @registrar ||= Invoice.find_by(reference_no: parsed_ref_number)&.buyer
end end
# For successful binding, reference number, invoice id and sum must match with the invoice # For successful binding, reference number, invoice id and sum must match with the invoice
def autobind_invoice def autobind_invoice(manual: false)
return if binded? return if binded?
return unless registrar return unless registrar
return unless invoice_num
return unless invoice return unless invoice
return unless invoice.payable? return unless invoice.payable?
return if invoice.total != sum channel = if manual
create_activity(registrar, invoice) 'admin_payment'
else
'system_payment'
end
create_internal_payment_record(channel: channel, invoice: invoice,
registrar: registrar)
end end
def bind_invoice(invoice_no) def create_internal_payment_record(channel: nil, invoice:, registrar:)
if channel.nil?
create_activity(invoice.buyer, invoice)
return
end
payment_order = PaymentOrder.new_with_type(type: channel, invoice: invoice)
payment_order.save!
if create_activity(registrar, invoice)
payment_order.paid!
else
payment_order.update(notes: 'Failed to create activity', status: 'failed')
end
end
def bind_invoice(invoice_no, manual: false)
if binded? if binded?
errors.add(:base, I18n.t('transaction_is_already_binded')) errors.add(:base, I18n.t('transaction_is_already_binded'))
return return
end end
invoice = Invoice.find_by(number: invoice_no) invoice = Invoice.find_by(number: invoice_no)
errors.add(:base, I18n.t('invoice_was_not_found')) unless invoice
validate_invoice_data(invoice)
return if errors.any?
unless invoice create_internal_payment_record(channel: (manual ? 'admin_payment' : nil), invoice: invoice,
errors.add(:base, I18n.t('invoice_was_not_found')) registrar: invoice.buyer)
return end
end
def validate_invoice_data(invoice)
if invoice.paid? if invoice.paid?
errors.add(:base, I18n.t('invoice_is_already_binded')) errors.add(:base, I18n.t('invoice_is_already_binded'))
return return
@ -70,23 +89,21 @@ class BankTransaction < ActiveRecord::Base
return return
end end
if invoice.total != sum errors.add(:base, I18n.t('invoice_and_transaction_sums_do_not_match')) if invoice.total != sum
errors.add(:base, I18n.t('invoice_and_transaction_sums_do_not_match'))
return
end
create_activity(invoice.buyer, invoice)
end end
def create_activity(registrar, invoice) def create_activity(registrar, invoice)
ActiveRecord::Base.transaction do activity = AccountActivity.new(
create_account_activity!(account: registrar.cash_account, account: registrar.cash_account, bank_transaction: self,
invoice: invoice, invoice: invoice, sum: invoice.subtotal,
sum: invoice.subtotal, currency: currency, description: description,
currency: currency, activity_type: AccountActivity::ADD_CREDIT
description: description, )
activity_type: AccountActivity::ADD_CREDIT) if activity.save
reset_pending_registrar_balance_reload reset_pending_registrar_balance_reload
true
else
false
end end
end end
@ -98,4 +115,12 @@ class BankTransaction < ActiveRecord::Base
registrar.settings['balance_auto_reload'].delete('pending') registrar.settings['balance_auto_reload'].delete('pending')
registrar.save! registrar.save!
end end
def parsed_ref_number
reference_no || ref_number_from_description
end
def ref_number_from_description
/(\d{7})/.match(description)[0]
end
end end

View file

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

View file

@ -1,4 +1,4 @@
class BlockedDomain < ActiveRecord::Base class BlockedDomain < ApplicationRecord
include Versions include Versions
before_save :generate_data before_save :generate_data
after_destroy :remove_data after_destroy :remove_data

View file

@ -1,6 +1,6 @@
require 'open3' require 'open3'
class Certificate < ActiveRecord::Base class Certificate < ApplicationRecord
include Versions include Versions
belongs_to :api_user belongs_to :api_user
@ -32,20 +32,21 @@ class Certificate < ActiveRecord::Base
errors.add(:base, I18n.t(:invalid_csr_or_crt)) errors.add(:base, I18n.t(:invalid_csr_or_crt))
end end
before_create :parse_metadata validate :assign_metadata, on: :create
def parse_metadata
if crt def assign_metadata
pc = parsed_crt.try(:subject).try(:to_s) || '' origin = crt ? parsed_crt : parsed_csr
cn = pc.scan(/\/CN=(.+)/).flatten.first parse_metadata(origin)
self.common_name = cn.split('/').first rescue NoMethodError
self.md5 = OpenSSL::Digest::MD5.new(parsed_crt.to_der).to_s errors.add(:base, I18n.t(:invalid_csr_or_crt))
self.interface = API end
elsif csr
pc = parsed_csr.try(:subject).try(:to_s) || '' def parse_metadata(origin)
cn = pc.scan(/\/CN=(.+)/).flatten.first pc = origin.subject.to_s
self.common_name = cn.split('/').first cn = pc.scan(%r{\/CN=(.+)}).flatten.first
self.interface = REGISTRAR self.common_name = cn.split('/').first
end self.md5 = OpenSSL::Digest::MD5.new(origin.to_der).to_s if crt
self.interface = crt ? API : REGISTRAR
end end
def parsed_crt def parsed_crt
@ -116,6 +117,7 @@ class Certificate < ActiveRecord::Base
-revoke #{crt_file.path} -key '#{ENV['ca_key_password']}' -batch") -revoke #{crt_file.path} -key '#{ENV['ca_key_password']}' -batch")
if err.match(/Data Base Updated/) || err.match(/ERROR:Already revoked/) if err.match(/Data Base Updated/) || err.match(/ERROR:Already revoked/)
self.revoked = true
save! save!
@cached_status = REVOKED @cached_status = REVOKED
else else

View file

@ -0,0 +1,3 @@
class CertificationRequest
extend ActiveModel::Translation
end

View file

@ -3,7 +3,7 @@ module Concerns::Contact::Transferable
included do included do
validates :auth_info, presence: true validates :auth_info, presence: true
after_initialize :generate_auth_info, if: 'new_record? && auth_info.blank?' after_initialize :generate_auth_info, if: -> { new_record? && auth_info.blank? }
end end
def transfer(new_registrar) def transfer(new_registrar)

View file

@ -0,0 +1,44 @@
# frozen_string_literal: true
module Concerns
module Domain
module Disputable
extend ActiveSupport::Concern
included do
validate :validate_disputed
end
def mark_as_disputed
statuses.push(DomainStatus::DISPUTED) unless statuses.include?(DomainStatus::DISPUTED)
save
end
def unmark_as_disputed
statuses.delete_if { |status| status == DomainStatus::DISPUTED }
save
end
def in_disputed_list?
@in_disputed_list ||= Dispute.active.find_by(domain_name: name).present?
end
def disputed?
Dispute.active.where(domain_name: name).any?
end
def validate_disputed
return if persisted? || !in_disputed_list?
if reserved_pw.blank?
errors.add(:base, :required_parameter_missing_disputed)
return false
end
return if Dispute.valid_auth?(name, reserved_pw)
errors.add(:base, :invalid_auth_information_reserved)
end
end
end
end

View file

@ -1,32 +1,116 @@
module Concerns::Domain::ForceDelete module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do
store_accessor :force_delete_data,
:force_delete_type,
:contact_notification_sent_date,
:template_name
scope :notification_not_sent,
lambda {
where("(force_delete_data->>'contact_notification_sent_date') is null")
}
end
class_methods do
def force_delete_scheduled
where('force_delete_start <= ?', Time.zone.now)
end
end
def force_delete_scheduled? def force_delete_scheduled?
statuses.include?(DomainStatus::FORCE_DELETE) statuses.include?(DomainStatus::FORCE_DELETE)
end end
def schedule_force_delete def should_notify_on_soft_force_delete?
force_delete_scheduled? && contact_notification_sent_date.blank? &&
force_delete_start.to_date <= Time.zone.now.to_date && force_delete_type.to_sym == :soft &&
!statuses.include?(DomainStatus::CLIENT_HOLD)
end
def client_holdable?
force_delete_scheduled? && !statuses.include?(DomainStatus::CLIENT_HOLD) &&
force_delete_start.present? && force_delete_lte_today && force_delete_lte_valid_date
end
def force_delete_lte_today
force_delete_start + Setting.expire_warning_period.days <= Time.zone.now
end
def force_delete_lte_valid_date
force_delete_start + Setting.expire_warning_period.days <= valid_to
end
def schedule_force_delete(type: :fast_track)
if discarded? if discarded?
raise StandardError, 'Force delete procedure cannot be scheduled while a domain is discarded' raise StandardError, 'Force delete procedure cannot be scheduled while a domain is discarded'
end end
type == :fast_track ? force_delete_fast_track : force_delete_soft
end
def add_force_delete_type(force_delete_type)
self.force_delete_type = force_delete_type
end
def force_delete_fast_track
preserve_current_statuses_for_force_delete preserve_current_statuses_for_force_delete
add_force_delete_statuses add_force_delete_statuses
self.force_delete_date = Time.zone.today + Setting.redemption_grace_period.days + 1.day add_force_delete_type(:fast)
self.force_delete_date = force_delete_fast_track_start_date + 1.day
self.force_delete_start = Time.zone.today + 1.day
stop_all_pending_actions stop_all_pending_actions
allow_deletion allow_deletion
save(validate: false) save(validate: false)
end end
def cancel_force_delete def force_delete_soft
restore_statuses_before_force_delete preserve_current_statuses_for_force_delete
remove_force_delete_statuses add_force_delete_statuses
self.force_delete_date = nil add_force_delete_type(:soft)
calculate_soft_delete_date
stop_all_pending_actions
allow_deletion
save(validate: false) save(validate: false)
end end
def clear_force_delete_data
self.force_delete_data = nil
end
def cancel_force_delete
restore_statuses_before_force_delete
remove_force_delete_statuses
clear_force_delete_data
self.force_delete_date = nil
self.force_delete_start = nil
save(validate: false)
registrar.notifications.create!(text: I18n.t('force_delete_cancelled', domain_name: name))
end
def outzone_date
(force_delete_start || valid_to) + Setting.expire_warning_period.days
end
def purge_date
(force_delete_date&.beginning_of_day || valid_to + Setting.expire_warning_period.days +
Setting.redemption_grace_period.days)
end
private private
def calculate_soft_delete_date
years = (valid_to.to_date - Time.zone.today).to_i / 365
soft_delete_dates(years) if years.positive?
end
def soft_delete_dates(years)
self.force_delete_start = valid_to - years.years + 1.day
self.force_delete_date = force_delete_start + Setting.expire_warning_period.days +
Setting.redemption_grace_period.days
end
def stop_all_pending_actions def stop_all_pending_actions
statuses.delete(DomainStatus::PENDING_UPDATE) statuses.delete(DomainStatus::PENDING_UPDATE)
statuses.delete(DomainStatus::PENDING_TRANSFER) statuses.delete(DomainStatus::PENDING_TRANSFER)
@ -35,7 +119,7 @@ module Concerns::Domain::ForceDelete
end end
def preserve_current_statuses_for_force_delete def preserve_current_statuses_for_force_delete
self.statuses_before_force_delete = statuses self.statuses_before_force_delete = statuses.clone
end end
def restore_statuses_before_force_delete def restore_statuses_before_force_delete
@ -47,25 +131,21 @@ module Concerns::Domain::ForceDelete
statuses << DomainStatus::FORCE_DELETE statuses << DomainStatus::FORCE_DELETE
statuses << DomainStatus::SERVER_RENEW_PROHIBITED statuses << DomainStatus::SERVER_RENEW_PROHIBITED
statuses << DomainStatus::SERVER_TRANSFER_PROHIBITED statuses << DomainStatus::SERVER_TRANSFER_PROHIBITED
statuses << DomainStatus::SERVER_UPDATE_PROHIBITED
statuses << DomainStatus::PENDING_DELETE
if (statuses & [DomainStatus::SERVER_HOLD, DomainStatus::CLIENT_HOLD]).empty?
statuses << DomainStatus::SERVER_MANUAL_INZONE
end
end end
def remove_force_delete_statuses def remove_force_delete_statuses
statuses.delete(DomainStatus::FORCE_DELETE) statuses.delete(DomainStatus::FORCE_DELETE)
statuses.delete(DomainStatus::SERVER_RENEW_PROHIBITED) statuses.delete(DomainStatus::SERVER_RENEW_PROHIBITED)
statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED) statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED)
statuses.delete(DomainStatus::SERVER_UPDATE_PROHIBITED) statuses.delete(DomainStatus::CLIENT_HOLD)
statuses.delete(DomainStatus::PENDING_DELETE)
statuses.delete(DomainStatus::SERVER_MANUAL_INZONE)
end end
def allow_deletion def allow_deletion
statuses.delete(DomainStatus::CLIENT_DELETE_PROHIBITED) statuses.delete(DomainStatus::CLIENT_DELETE_PROHIBITED)
statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED) statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED)
end end
def force_delete_fast_track_start_date
Time.zone.today + Setting.expire_warning_period.days + Setting.redemption_grace_period.days
end
end end

View file

@ -57,7 +57,8 @@ module Concerns::Domain::Transferable
def transfer_domain_contacts(new_registrar) def transfer_domain_contacts(new_registrar)
copied_ids = [] copied_ids = []
contacts.each do |contact| domain_contacts.each do |dc|
contact = Contact.find(dc.contact_id)
next if copied_ids.include?(contact.id) || contact.registrar == new_registrar next if copied_ids.include?(contact.id) || contact.registrar == new_registrar
if registrant_id_was == contact.id # registrant was copied previously, do not copy it again if registrant_id_was == contact.id # registrant was copied previously, do not copy it again
@ -66,7 +67,11 @@ module Concerns::Domain::Transferable
oc = contact.transfer(new_registrar) oc = contact.transfer(new_registrar)
end end
domain_contacts.where(contact_id: contact.id).update_all({ contact_id: oc.id }) # n+1 workaround if domain_contacts.find_by(contact_id: oc.id, domain_id: id, type: dc.type).present?
dc.destroy
else
dc.update(contact_id: oc.id)
end
copied_ids << contact.id copied_ids << contact.id
end end
end end

View file

@ -0,0 +1,91 @@
module Concerns
module EmailVerifable
extend ActiveSupport::Concern
def email_verification
@email_verification ||= EmailAddressVerification.find_or_create_by(email: unicode_email,
domain: domain(email))
end
def billing_email_verification
return unless attribute_names.include?('billing_email')
@billing_email_verification ||= EmailAddressVerification
.find_or_create_by(email: unicode_billing_email,
domain: domain(billing_email))
end
class_methods do
def domain(email)
Mail::Address.new(email).domain&.downcase || 'not_found'
rescue Mail::Field::IncompleteParseError
'not_found'
end
def local(email)
Mail::Address.new(email).local&.downcase || email
rescue Mail::Field::IncompleteParseError
email
end
def punycode_to_unicode(email)
return email if domain(email) == 'not_found'
local = local(email)
domain = SimpleIDN.to_unicode(domain(email))
"#{local}@#{domain}"&.downcase
end
def unicode_to_punycode(email)
return email if domain(email) == 'not_found'
local = local(email)
domain = SimpleIDN.to_ascii(domain(email))
"#{local}@#{domain}"&.downcase
end
end
def unicode_billing_email
self.class.punycode_to_unicode(billing_email)
end
def unicode_email
self.class.punycode_to_unicode(email)
end
def domain(email)
SimpleIDN.to_unicode(self.class.domain(email))
end
def punycode_to_unicode(email)
self.class.punycode_to_unicode(email)
end
def correct_email_format
return if email.blank?
result = email_verification.verify
process_result(result: result, field: :email)
end
def correct_billing_email_format
return if email.blank?
result = billing_email_verification.verify
process_result(result: result, field: :billing_email)
end
# rubocop:disable Metrics/LineLength
def process_result(result:, field:)
case result[:errors].keys.first
when :smtp
errors.add(field, I18n.t('activerecord.errors.models.contact.attributes.email.email_smtp_check_error'))
when :mx
errors.add(field, I18n.t('activerecord.errors.models.contact.attributes.email.email_mx_check_error'))
when :regex
errors.add(field, I18n.t('activerecord.errors.models.contact.attributes.email.email_regex_check_error'))
end
end
# rubocop:enable Metrics/LineLength
end
end

View file

@ -20,7 +20,7 @@ module EppErrors
epp_errors << collect_parent_errors(attr, errors) epp_errors << collect_parent_errors(attr, errors)
end end
errors[:epp_errors] = epp_errors errors.add(:epp_errors, epp_errors)
errors[:epp_errors].flatten! errors[:epp_errors].flatten!
end end

View file

@ -0,0 +1,34 @@
module Concerns
module Invoice
module BookKeeping
extend ActiveSupport::Concern
def as_directo_json
invoice = ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(self))
invoice['customer'] = compose_directo_customer
invoice['issue_date'] = issue_date.strftime('%Y-%m-%d')
invoice['transaction_date'] = account_activity
.bank_transaction&.paid_at&.strftime('%Y-%m-%d')
invoice['language'] = buyer.language == 'en' ? 'ENG' : ''
invoice['invoice_lines'] = compose_directo_product
invoice
end
def compose_directo_product
[{ 'product_id': Setting.directo_receipt_product_name, 'description': order,
'quantity': 1, 'price': ActionController::Base.helpers.number_with_precision(
subtotal, precision: 2, separator: '.'
) }].as_json
end
def compose_directo_customer
{
'code': buyer.accounting_customer_code,
'destination': buyer_country_code,
'vat_reg_no': buyer_vat_no,
}.as_json
end
end
end
end

View file

@ -0,0 +1,34 @@
module Concerns
module Job
module ForceDelete
extend ActiveSupport::Concern
class_methods do
def start_client_hold
log_prepare_client_hold
::PaperTrail.request.whodunnit = "cron - #{__method__}"
::Domain.force_delete_scheduled.each do |domain|
proceed_client_hold(domain: domain)
end
log_end_end_force_delete_job
end
def proceed_client_hold(domain:)
notify_on_grace_period(domain) if domain.should_notify_on_soft_force_delete?
return unless domain.client_holdable?
domain.statuses << DomainStatus::CLIENT_HOLD
log_start_client_hold(domain)
domain.save(validate: false)
notify_client_hold(domain)
log_end_end_client_hold(domain)
end
end
end
end
end

View file

@ -0,0 +1,34 @@
module Concerns
module Job
module ForceDeleteLogging
extend ActiveSupport::Concern
class_methods do
def log_prepare_client_hold
return if Rails.env.test?
STDOUT << "#{Time.zone.now.utc} - Setting client_hold to domains\n"
end
def log_start_client_hold(domain)
return if Rails.env.test?
STDOUT << "#{Time.zone.now.utc} DomainCron.start_client_hold: ##{domain.id} "\
"(#{domain.name}) #{domain.changes}\n"
end
def log_end_end_client_hold(domain)
return if Rails.env.test?
STDOUT << "#{Time.zone.now.utc} - Successfully set client_hold on (#{domain.name})"
end
def log_end_end_force_delete_job
return if Rails.env.test?
STDOUT << "#{Time.zone.now.utc} - All client_hold setting are done\n"
end
end
end
end
end

View file

@ -0,0 +1,31 @@
module Concerns
module Job
module ForceDeleteNotify
extend ActiveSupport::Concern
class_methods do
def notify_client_hold(domain)
domain.registrar.notifications.create!(text: I18n.t('force_delete_set_on_domain',
domain_name: domain.name,
outzone_date: domain.outzone_date,
purge_date: domain.purge_date))
end
def notify_on_grace_period(domain)
domain.registrar.notifications.create!(text: I18n.t('grace_period_started_domain',
domain_name: domain.name,
date: domain.force_delete_start))
send_mail(domain)
domain.update(contact_notification_sent_date: Time.zone.today)
end
def send_mail(domain)
DomainDeleteMailer.forced(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant,
template_name: domain.template_name).deliver_now
end
end
end
end
end

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