diff --git a/.gitignore b/.gitignore index b42af1d24..175f485fc 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ capybara-*.html /spec/tmp **.orig config/initializers/secret_token.rb -config/application.yml config/secrets.yml config/database.yml /export @@ -26,3 +25,6 @@ todo # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: .rvmrc + +# Ignore application configuration +/config/application.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index e9fd7e7e8..cc0bd3e74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +27.02.2015 + +* Simplified config/application-example.yml, + now system will check if all required settings are present in application.yml + 19.02.2015 * Cetrificate only enabled, please setup certificates following doc/certificate.md document. diff --git a/Gemfile b/Gemfile index 68a2b9571..e0bf28b53 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,9 @@ gem 'rails', '4.2.0' gem 'iso8601', '~> 0.8.2' # for dates and times gem 'hashie_rails', '~> 0.0.1' +# load env +gem 'figaro', '~> 1.1.0' + # model related gem 'pg', '~> 0.18.0' gem 'ransack', '~> 1.5.1' # for searching diff --git a/Gemfile.lock b/Gemfile.lock index b798b512b..478d7604a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -152,6 +152,8 @@ GEM i18n (~> 0.5) fastercsv (1.5.5) ffi (1.9.6) + figaro (1.1.0) + thor (~> 0.14) flay (2.4.0) ruby_parser (~> 3.0) sexp_processor (~> 4.0) @@ -459,6 +461,7 @@ DEPENDENCIES epp-xml (~> 0.10.4) fabrication (~> 2.12.2) faker (~> 1.3.0) + figaro (~> 1.1.0) grape (~> 0.10.1) guard (~> 2.6.1) guard-rails (~> 0.7.0) diff --git a/Guardfile b/Guardfile index 358d58e80..e6d0a443a 100644 --- a/Guardfile +++ b/Guardfile @@ -3,11 +3,11 @@ group :red_green_refactor, halt_on_fail: true do # be sure you have apache2 configured to # accept EPP request on port 701, what proxy to 8989. # port and environment is just for correct notification, all is overwritten by CLI - guard :rails, port: 8989, environment: 'test' do - # guard :rails, port: 8989, environment: 'test', CLI: 'RAILS_ENV=test unicorn -p 8989' do - watch('Gemfile.lock') - watch(%r{^(config|lib)/.*}) - end + # guard :rails, port: 8989, environment: 'test' do + # # guard :rails, port: 8989, environment: 'test', CLI: 'RAILS_ENV=test unicorn -p 8989' do + # watch('Gemfile.lock') + # watch(%r{^(config|lib)/.*}) + # end guard :rspec, cmd: 'spring rspec', notification: false do watch(%r{^spec/.+_spec\.rb$}) diff --git a/README.md b/README.md index 24740e064..0380f6a75 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Installation ### Registry app -Usual Rails 4 app installation (rbenv install is under Debian build doc) +Registry based on Rails 4 installation (rbenv install is under Debian build doc) Manual demo install and database setup: @@ -32,44 +32,11 @@ Manual demo install and database setup: cd demo-registry rbenv local 2.2.0 bundle + cp config/application-example.yml config/application.yml # and edit it cp config/database-example.yml config/database.yml # and edit it - cp config/initializers/devise_secret_example.rb.txt config/initializers/devise_secret.rb # and edit + bundle exec rake db:all:setup # for production, please follow deployment howto bundle exec rake assets:precompile -Create registry database manually, example: - - create database registry_production owner registry encoding 'UTF-8' LC_COLLATE 'et_EE.utf8' LC_CTYPE 'et_EE.utf8' template template0; - rake db:schema:load - rake db:seeds - -Or create all databases: - - rake db:all:setup # will create all databases and loads all schemas - rake db:all:create # creates all databases - rake db:all:schema:load # loads all schemas - rake db:all:schema:dump # dumps all schemas - -Production install (database schema should be loaded and seeds should be present) - - # at your local machine - git clone git@github.com:internetee/registry.git - cd registry - rbenv local 2.2.0 # more info about rbenv at debian doc - gem install mina - mina pr setup # one time, only creates missing directories - ssh registry - - # at your server - cd registry - cp current/config/application-example.yml shared/config/application.yml # and edit it - cp current/config/database-example.yml shared/config/database.yml # and edit it - - vi /etc/apache2/sites-enabled/registry.conf # add conf and all needed serts - vi /etc/apache2/sites-enabled/epp.conf # add epp conf, restart apache - exit - # at your local machine - mina pr deploy # this is command you use in every application code update - ### Apache with patched mod_epp (Debian 7/Ubuntu 14.04 LTS) sudo apt-get install apache2 @@ -186,11 +153,22 @@ All registry demo data can be found at: Initially you can use two type of users: admin users and EPP users. + ### Certificates setup * [Certificates setup](/doc/certificates.md) +### Deployment + +* [Application build and update](/doc/application_build_doc.md) + + +### Autotesting + +* [Testing](/doc/testing.md) + + ### EPP web client Please follow EPP web client readme: @@ -205,89 +183,6 @@ Please follow WHOIS server readme: https://github.com/internetee/whois -Deployment ----------- - -* [Debian build](/doc/debian_build_doc.md) -* [Application build and update](/doc/application_build_doc.md) - -CRON ----- - -Crontab can be setup after deploy. Jobs can be viewed [here](/config/schedule.rb). - - mina pr cron:setup # to update the crontab. - mina pr cron:clear # to clear crontab. - -Autotesting ------------ - -* Before running tests for the first time: `RAILS_ENV=test rake db:seed` -* Run tests: `rake` -* Run EPP tests: `rake test:epp` -* Run all but EPP tests: `rake test:other` - -To see internal errors while testing EPP - - unicorn -E test -p 8989 - rake spec:epp - -### Apache mod_epp autotesting/debugging - -Autotesting Apache mod_epp without Registry app. - - sudo apt-get install apache2-dbg - -Includes htpasswd command to generate authentication files - - sudo apt-get install apache2-utils - -For manual debugging purposes, standalone CGI scripts can be used: -This needs a static greeting file, so you will have to make /var/www writable. - -```apache - - - Options ExecCGI - SetHandler cgi-script - - - Listen 1700 - - - EPPEngine On - EPPCommandRoot /cgi-bin/epp/command - EPPSessionRoot /cgi-bin/epp/session - EPPErrorRoot /cgi-bin/epp/error - - Alias /cgi-bin/epp/session/hello /var/www/html/epp/session-hello - - Alias /cgi-bin/epp/session/login /usr/lib/cgi-bin/epp/session-login - Alias /cgi-bin/epp/session/logout /usr/lib/cgi-bin/epp/session-logout - Alias /cgi-bin/epp/error/schema /usr/lib/cgi-bin/epp/error-schema - Alias /cgi-bin/epp/command/create /usr/lib/cgi-bin/epp/create - Alias /cgi-bin/epp/command/info /usr/lib/cgi-bin/epp/info - - EPPAuthURI /epp/auth/login - - AuthType Basic - AuthName "EPP" - AuthUserFile /etc/apache2/htpasswd - require valid-user - - - -``` - - sudo a2enmod cgi - sudo a2enmod authn_file # will be used for non implicit authentication URIs - sudo htpasswd -c /etc/apache2/htpasswd test - Type "test" when prompted - cd /usr/lib/cgi-bin - mkdir epp - -Copy the files from $mod_epp/examples/cgis to /usr/lib/cgi-bin/epp - ## Code Status Alpha release status, only model tests: diff --git a/app/controllers/epp/contacts_controller.rb b/app/controllers/epp/contacts_controller.rb index 5af05d9fd..d93916055 100644 --- a/app/controllers/epp/contacts_controller.rb +++ b/app/controllers/epp/contacts_controller.rb @@ -17,9 +17,7 @@ class Epp::ContactsController < EppController def create authorize! :create, Epp::Contact - - @contact = Epp::Contact.new(params[:parsed_frame]) - @contact.registrar = current_user.registrar + @contact = Epp::Contact.new(params[:parsed_frame], current_user.registrar) if @contact.save render_epp_response '/epp/contacts/create' diff --git a/app/controllers/epp/sessions_controller.rb b/app/controllers/epp/sessions_controller.rb index f12b2e56d..181cc19ac 100644 --- a/app/controllers/epp/sessions_controller.rb +++ b/app/controllers/epp/sessions_controller.rb @@ -9,7 +9,7 @@ class Epp::SessionsController < EppController # rubocop: disable Metrics/CyclomaticComplexity def login cert_valid = true - if request.ip == APP_CONFIG['webclient_ip'] + if request.ip == ENV['webclient_ip'] @api_user = ApiUser.find_by(login_params) else if request.env['HTTP_SSL_CLIENT_S_DN_CN'] != login_params[:username] diff --git a/app/controllers/epp_controller.rb b/app/controllers/epp_controller.rb index 89623117c..a0985be4a 100644 --- a/app/controllers/epp_controller.rb +++ b/app/controllers/epp_controller.rb @@ -103,6 +103,7 @@ class EppController < ApplicationController 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 @@ -112,7 +113,7 @@ class EppController < ApplicationController end epp_errors << { code: '2003', - msg: I18n.t('errors.messages.required_parameter_missing', key: full_selector) + msg: I18n.t('errors.messages.required_parameter_missing', key: "#{full_selector} [#{attr}]") } if missing end diff --git a/app/models/api_user.rb b/app/models/api_user.rb index cd07282b7..d95ce8414 100644 --- a/app/models/api_user.rb +++ b/app/models/api_user.rb @@ -20,7 +20,7 @@ class ApiUser < User after_initialize :set_defaults def set_defaults return unless new_record? - self.active = true + self.active = true unless active_changed? end def registrar_typeahead diff --git a/app/models/api_user_deprecated.rb b/app/models/api_user_deprecated.rb index f44719fbb..c809564ea 100644 --- a/app/models/api_user_deprecated.rb +++ b/app/models/api_user_deprecated.rb @@ -32,10 +32,10 @@ class ApiUserDeprecated < ActiveRecord::Base csr_file.rewind crt_file = Tempfile.new('client_crt') - _out, err, _st = Open3.capture3("openssl ca -keyfile #{APP_CONFIG['ca_key_path']} \ - -cert #{APP_CONFIG['ca_cert_path']} \ + _out, err, _st = Open3.capture3("openssl ca -keyfile #{ENV['ca_key_path']} \ + -cert #{ENV['ca_cert_path']} \ -extensions usr_cert -notext -md sha256 \ - -in #{csr_file.path} -out #{crt_file.path} -key '#{APP_CONFIG['ca_key_password']}' -batch") + -in #{csr_file.path} -out #{crt_file.path} -key '#{ENV['ca_key_password']}' -batch") if err.match(/Data Base Updated/) crt_file.rewind diff --git a/app/models/certificate.rb b/app/models/certificate.rb index 30cbbe949..51d4ac5e4 100644 --- a/app/models/certificate.rb +++ b/app/models/certificate.rb @@ -33,7 +33,7 @@ class Certificate < ActiveRecord::Base @cached_status = EXPIRED end - crl = OpenSSL::X509::CRL.new(File.open(APP_CONFIG['crl_path']).read) + crl = OpenSSL::X509::CRL.new(File.open(ENV['crl_path']).read) return @cached_status unless crl.revoked.map(&:serial).include?(parsed_crt.serial) @cached_status = REVOKED @@ -45,10 +45,10 @@ class Certificate < ActiveRecord::Base csr_file.rewind crt_file = Tempfile.new('client_crt') - _out, err, _st = Open3.capture3("openssl ca -keyfile #{APP_CONFIG['ca_key_path']} \ - -cert #{APP_CONFIG['ca_cert_path']} \ + _out, err, _st = Open3.capture3("openssl ca -keyfile #{ENV['ca_key_path']} \ + -cert #{ENV['ca_cert_path']} \ -extensions usr_cert -notext -md sha256 \ - -in #{csr_file.path} -out #{crt_file.path} -key '#{APP_CONFIG['ca_key_password']}' -batch") + -in #{csr_file.path} -out #{crt_file.path} -key '#{ENV['ca_key_password']}' -batch") if err.match(/Data Base Updated/) crt_file.rewind @@ -67,9 +67,9 @@ class Certificate < ActiveRecord::Base crt_file.write(crt) crt_file.rewind - _out, err, _st = Open3.capture3("openssl ca -keyfile #{APP_CONFIG['ca_key_path']} \ - -cert #{APP_CONFIG['ca_cert_path']} \ - -revoke #{crt_file.path} -key '#{APP_CONFIG['ca_key_password']}' -batch") + _out, err, _st = Open3.capture3("openssl ca -keyfile #{ENV['ca_key_path']} \ + -cert #{ENV['ca_cert_path']} \ + -revoke #{crt_file.path} -key '#{ENV['ca_key_password']}' -batch") if err.match(/Data Base Updated/) || err.match(/ERROR:Already revoked/) save! @@ -81,8 +81,8 @@ class Certificate < ActiveRecord::Base return false end - _out, _err, _st = Open3.capture3("openssl ca -keyfile #{APP_CONFIG['ca_key_path']} \ - -cert #{APP_CONFIG['ca_cert_path']} \ - -gencrl -out #{APP_CONFIG['crl_path']} -key '#{APP_CONFIG['ca_key_password']}' -batch") + _out, _err, _st = Open3.capture3("openssl ca -keyfile #{ENV['ca_key_path']} \ + -cert #{ENV['ca_cert_path']} \ + -gencrl -out #{ENV['crl_path']} -key '#{ENV['ca_key_password']}' -batch") end end diff --git a/app/models/concerns/epp_errors.rb b/app/models/concerns/epp_errors.rb index 4d95cea27..cf3824260 100644 --- a/app/models/concerns/epp_errors.rb +++ b/app/models/concerns/epp_errors.rb @@ -3,42 +3,43 @@ module EppErrors def construct_epp_errors epp_errors = [] - errors.messages.each do |key, values| - key = key.to_s.split('.')[0].to_sym - next if key == :epp_errors + errors.messages.each do |attr, errors| + attr = attr.to_s.split('.')[0].to_sym + next if attr == :epp_errors - if self.class.reflect_on_association(key) - epp_errors << collect_child_errors(key) + if self.class.reflect_on_association(attr) + epp_errors << collect_child_errors(attr) end - epp_errors << collect_parent_errors(values) + epp_errors << collect_parent_errors(attr, errors) end errors[:epp_errors] = epp_errors errors[:epp_errors].flatten! end - def collect_parent_errors(values) - epp_errors = [] - values = [values] if values.is_a?(String) + def collect_parent_errors(attr, errors) + errors = [errors] if errors.is_a?(String) - values.each do |err| + epp_errors = [] + errors.each do |err| code, value = find_epp_code_and_value(err) next unless code - epp_errors << { code: code, msg: err, value: value } + msg = attr.to_sym == :base ? err : "#{err} [#{attr}]" + epp_errors << { code: code, msg: msg, value: value } end epp_errors end - def collect_child_errors(key) - macro = self.class.reflect_on_association(key).macro + def collect_child_errors(attr) + macro = self.class.reflect_on_association(attr).macro multi = [:has_and_belongs_to_many, :has_many] # single = [:belongs_to, :has_one] epp_errors = [] - send(key).each do |x| - x.errors.messages.each do |_key, values| - epp_errors << x.collect_parent_errors(values) + send(attr).each do |x| + x.errors.messages.each do |attribute, errors| + epp_errors << x.collect_parent_errors(attribute, errors) end end if multi.include?(macro) diff --git a/app/models/contact.rb b/app/models/contact.rb index 722e4de33..da8a3f651 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -22,7 +22,11 @@ class Contact < ActiveRecord::Base format: { with: /\d{4}-\d{2}-\d{2}/, message: :invalid_birthday_format }, if: proc { |c| c.ident_type == 'birthday' } validates :ident_country_code, presence: true, if: proc { |c| %w(bic priv).include? c.ident_type } - validates :code, uniqueness: { message: :epp_id_taken } + validates :code, + uniqueness: { message: :epp_id_taken }, + format: { with: /\A[\w\-\:]*\Z/i }, + length: { maximum: 100 } + validate :ident_valid_format? delegate :street, to: :address @@ -99,15 +103,27 @@ class Contact < ActiveRecord::Base ident_type != IDENT_TYPE_BIC end - # generate random id for contact def generate_code - self.code = SecureRandom.hex(4) + self.code = SecureRandom.hex(4) if code.blank? end def generate_auth_info + return if @generate_auth_info_disabled self.auth_info = SecureRandom.hex(16) end + def disable_generate_auth_info! # needed for testing + @generate_auth_info_disabled = true + end + + def auth_info=(pw) + self[:auth_info] = pw if new_record? + end + + def code=(code) + self[:code] = code if new_record? + end + # Find a way to use self.domains with contact def domains_owned Domain.where(owner_contact_id: id) diff --git a/app/models/epp/contact.rb b/app/models/epp/contact.rb index 0a6c14020..d9df7f2ae 100644 --- a/app/models/epp/contact.rb +++ b/app/models/epp/contact.rb @@ -45,9 +45,22 @@ class Epp::Contact < Contact # rubocop: enable Metrics/PerceivedComplexity # rubocop: enable Metrics/CyclomaticComplexity - def new(frame) + def new(frame, registrar) return super if frame.blank? - super(attrs_from(frame)) + + custom_code = + if frame.css('id').present? + "#{registrar.code}:#{frame.css('id').text.parameterize}" + else + nil + end + + super( + attrs_from(frame).merge( + code: custom_code, + registrar: registrar + ) + ) end def legal_document_attrs(legal_frame) diff --git a/app/models/registrar.rb b/app/models/registrar.rb index 2078226b2..e895273b3 100644 --- a/app/models/registrar.rb +++ b/app/models/registrar.rb @@ -9,10 +9,18 @@ class Registrar < ActiveRecord::Base validates :name, :reg_no, :country_code, :email, presence: true validates :name, :reg_no, uniqueness: true + validate :set_code, if: :new_record? after_save :touch_domains_version validates :email, :billing_email, format: /@/, allow_blank: true + class << self + def search_by_query(query) + res = search(name_or_reg_no_cont: query).result + res.reduce([]) { |o, v| o << { id: v[:id], display_key: "#{v[:name]} (#{v[:reg_no]})" } } + end + end + def domain_transfers at = DomainTransfer.arel_table DomainTransfer.where( @@ -34,10 +42,23 @@ class Registrar < ActiveRecord::Base Country.new(country_code) end - class << self - def search_by_query(query) - res = search(name_or_reg_no_cont: query).result - res.reduce([]) { |o, v| o << { id: v[:id], display_key: "#{v[:name]} (#{v[:reg_no]})" } } + def code=(code) + self[:code] = code if new_record? + end + + private + + def set_code + return false if name.blank? + new_code = name.parameterize + + # ensure code is always uniq automatically for a new record + seq = 1 + while self.class.find_by_code(new_code) + new_code += seq.to_s + seq += 1 end + + self.code = new_code end end diff --git a/app/models/zonefile_setting.rb b/app/models/zonefile_setting.rb index cdeb8087d..c9cac6154 100644 --- a/app/models/zonefile_setting.rb +++ b/app/models/zonefile_setting.rb @@ -18,7 +18,7 @@ class ZonefileSetting < ActiveRecord::Base "select generate_zonefile('#{origin}')" )[0]['generate_zonefile'] - File.open("#{APP_CONFIG['zonefile_export_dir']}/#{filename}", 'w') { |f| f.write(zf) } + File.open("#{ENV['zonefile_export_dir']}/#{filename}", 'w') { |f| f.write(zf) } STDOUT << "#{Time.now.utc} - Successfully generated zonefile #{filename}\n" end diff --git a/app/views/layouts/application.haml b/app/views/layouts/application.haml index 05e513372..13ab2aab7 100644 --- a/app/views/layouts/application.haml +++ b/app/views/layouts/application.haml @@ -21,7 +21,7 @@ %span.icon-bar %span.icon-bar = link_to admin_dashboard_path, class: 'navbar-brand' do - = APP_CONFIG['app_name'] + = ENV['app_name'] - if unstable_env.present? .text-center %small{style: 'color: #0074B3;'}= unstable_env diff --git a/bin/docker-robot b/bin/docker-robot deleted file mode 100755 index fe41bd1f1..000000000 --- a/bin/docker-robot +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -# -# For docker -# - -# cd to Rails root directory -cd "$(dirname "$0")"; cd .. - -bin/update-repo -bin/robot diff --git a/bin/robot b/bin/robot index 28fbde348..9134a9137 100755 --- a/bin/robot +++ b/bin/robot @@ -16,14 +16,14 @@ export RAILS_ENV=test cd "$(dirname "$0")"; cd .. cp config/application-example.yml config/application.yml -# create manually config/database.yml +cp config/secrets-example.yml config/secrets.yml +cp config/database-robot.yml config/database.yml +# under jenkins use rbenv-plugin wrapper bundle install -RAILS_ENV=test bundle exec rake db:drop -RAILS_ENV=test bundle exec rake db:all:create -RAILS_ENV=test bundle exec rake db:all:schema:load -RAILS_ENV=test bundle exec rake db:seed +RAILS_ENV=test bundle exec rake db:all:drop +RAILS_ENV=test bundle exec rake db:all:setup RAILS_ENV=test bundle exec rake assets:precompile echo "GIT_LAST_COMMITS" @@ -36,6 +36,10 @@ RCODE=$? echo "END_OF_RUBOCOP_RESULTS" echo "TEST_RESULTS" +# basic test +# ROBOT=true bundle exec rake + +# all tests with EPP ROBOT=true bundle exec rake test TCODE=$? echo "END_OF_TEST_RESULTS" @@ -45,7 +49,7 @@ bundle exec bundle-audit update bundle exec bundle-audit BCODE=$? BCODE=0 # tmp -bundle exec brakeman +bundle exec brakeman -q echo "END_OF_SECURITY_RESULTS" # update code review diff --git a/config/application-example.yml b/config/application-example.yml index f5b0bf2ac..02d1cc7e2 100644 --- a/config/application-example.yml +++ b/config/application-example.yml @@ -1,33 +1,28 @@ -defaults: &defaults - app_name: .EE Registry - zonefile_export_dir: 'export/zonefiles' +# Be sure to restart your server when you modify settings. - # You can use `rake secret` to generate a secure secret key. - # Your secret key is used for verifying the integrity of signed cookies. - # If you change this key, all old signed cookies will become invalid! - secret_key_base: please-change-it-you-can-generate-it-with-rake-secret - devise_secret: please-change-it-you-can-generate-it-with-rake-secret +app_name: .EE Registry +zonefile_export_dir: 'export/zonefiles' - # Used by registry admin server: - crl_path: '/home/registry/registry/shared/ca/crl/crl.pem' - ca_cert_path: '/home/registry/registry/shared/ca/certs/ca.crt.pem' - ca_key_path: '/home/registry/registry/shared/ca/private/ca.key.pem' - ca_key_password: 'your-root-key-password' +# You can use `rake secret` to generate a secure secret key. +# Your secret key is used for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! +secret_key_base: please-change-it-you-can-generate-it-with-rake-secret +devise_secret: please-change-it-you-can-generate-it-with-rake-secret - # Used by EPP server - webclient_ip: '54.154.91.240' +# Used by admin server, you can leave those empty for when running EPP server: +crl_path: '/home/registry/registry/shared/ca/crl/crl.pem' +ca_cert_path: '/home/registry/registry/shared/ca/certs/ca.crt.pem' +ca_key_path: '/home/registry/registry/shared/ca/private/ca.key.pem' +ca_key_password: 'your-root-key-password' -development: - <<: *defaults +# Used only by EPP server, you can leave it empty when running admin server: +webclient_ip: '127.0.0.1' +# autotest config overwrites test: - <<: *defaults + webclient_ip: '127.0.0.1' # it should match to localhost ip address + crl_path: '/var/lib/jenkins/workspace/registry/ca/crl/crl.pem' + ca_cert_path: '/var/lib/jenkins/workspace/registry/ca/certs/ca.crt.pem' + ca_key_path: '/var/lib/jenkins/workspace/registry/ca/private/ca.key.pem' + ca_key_password: 'test' -alpha: - <<: *defaults - -staging: - <<: *defaults - -production: - <<: *defaults diff --git a/config/database-robot.yml b/config/database-robot.yml new file mode 100644 index 000000000..b38a048a2 --- /dev/null +++ b/config/database-robot.yml @@ -0,0 +1,19 @@ +default: &default + host: localhost + adapter: postgresql + encoding: unicode + pool: 5 + username: test + password: test + +test: + <<: *default + database: registry_test + +whois_test: + <<: *default + database: registry_whois_test + +api_log_test: + <<: *default + database: registry_api_log_test diff --git a/config/initializers/app_config.rb b/config/initializers/app_config.rb deleted file mode 100644 index d76066b1a..000000000 --- a/config/initializers/app_config.rb +++ /dev/null @@ -1,2 +0,0 @@ -APP_CONFIG = YAML.load_file("#{Rails.root}/config/application.yml")[Rails.env] -Registry::Application.config.secret_token = APP_CONFIG['secret_key_base'] diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 8bbe137e2..6415ada3d 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -4,7 +4,7 @@ Devise.setup do |config| # The secret key used by Devise. Devise uses this key to generate # random tokens. Changing this key will render invalid all existing # confirmation, reset password and unlock tokens in the database. - config.secret_key = APP_CONFIG['devise_secret'] + config.secret_key = ENV['devise_secret'] # ==> Mailer Configuration # Configure the e-mail address which will be shown in Devise::Mailer, diff --git a/config/initializers/env_required.rb b/config/initializers/env_required.rb new file mode 100644 index 000000000..c79520166 --- /dev/null +++ b/config/initializers/env_required.rb @@ -0,0 +1,13 @@ +required = %w( + app_name + zonefile_export_dir + secret_key_base + devise_secret + crl_path + ca_cert_path + ca_key_path + ca_key_password + webclient_ip +) + +Figaro.require_keys(required) diff --git a/config/initializers/initial_settings.rb b/config/initializers/initial_settings.rb index 84090c28d..5458b6d2e 100644 --- a/config/initializers/initial_settings.rb +++ b/config/initializers/initial_settings.rb @@ -1,4 +1,5 @@ -if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('settings') # otherwise rake not working 100% +# otherwise rake not working 100% +if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('settings') Setting.disclosure_name = true if Setting.disclosure_name.nil? Setting.disclosure_name = true if Setting.disclosure_name.nil? Setting.disclosure_org_name = true if Setting.disclosure_org_name.nil? diff --git a/config/initializers/set_secret.rb b/config/initializers/set_secret.rb new file mode 100644 index 000000000..ed1dbae7f --- /dev/null +++ b/config/initializers/set_secret.rb @@ -0,0 +1 @@ +Registry::Application.config.secret_token = ENV['secret_key_base'] diff --git a/db/migrate/20150227113121_change_api_user_default_value.rb b/db/migrate/20150227113121_change_api_user_default_value.rb new file mode 100644 index 000000000..614abb587 --- /dev/null +++ b/db/migrate/20150227113121_change_api_user_default_value.rb @@ -0,0 +1,5 @@ +class ChangeApiUserDefaultValue < ActiveRecord::Migration + def change + change_column_default :users, :active, nil + end +end diff --git a/db/migrate/20150303130729_add_code_to_registrar.rb b/db/migrate/20150303130729_add_code_to_registrar.rb new file mode 100644 index 000000000..6dea363fe --- /dev/null +++ b/db/migrate/20150303130729_add_code_to_registrar.rb @@ -0,0 +1,6 @@ +class AddCodeToRegistrar < ActiveRecord::Migration + def change + add_column :registrars, :code, :string + add_index :registrars, :code + end +end diff --git a/db/migrate/20150303151224_data_update_regisntrar_codes.rb b/db/migrate/20150303151224_data_update_regisntrar_codes.rb new file mode 100644 index 000000000..40d2b31cd --- /dev/null +++ b/db/migrate/20150303151224_data_update_regisntrar_codes.rb @@ -0,0 +1,11 @@ +class DataUpdateRegisntrarCodes < ActiveRecord::Migration + def change + puts 'Registrar code updates:' + Registrar.all.each do |r| + next if r.code.present? + r[:code] = r.name.parameterize + puts "#{r.id}: #{r.changes.inspect}" + r.save! + end + end +end diff --git a/db/schema.rb b/db/schema.rb index cb37d9166..fdedb6f22 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150223104842) do +ActiveRecord::Schema.define(version: 20150303151224) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -611,8 +611,11 @@ ActiveRecord::Schema.define(version: 20150223104842) do t.string "city" t.string "street" t.string "zip" + t.string "code" end + add_index "registrars", ["code"], name: "index_registrars_on_code", using: :btree + create_table "reserved_domains", force: :cascade do |t| t.string "name" t.datetime "created_at" @@ -640,19 +643,19 @@ ActiveRecord::Schema.define(version: 20150223104842) do t.datetime "created_at" t.datetime "updated_at" t.string "email" - t.integer "sign_in_count", default: 0, null: false + t.integer "sign_in_count", default: 0, null: false t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" t.inet "current_sign_in_ip" t.inet "last_sign_in_ip" t.string "identity_code" t.integer "country_id" - t.string "roles", array: true + t.string "roles", array: true t.string "creator_str" t.string "updator_str" t.string "country_code" t.integer "registrar_id" - t.boolean "active", default: false + t.boolean "active" t.text "csr" t.text "crt" t.string "type" diff --git a/doc/application_build_doc.md b/doc/application_build_doc.md index bd817b08b..53c93415b 100644 --- a/doc/application_build_doc.md +++ b/doc/application_build_doc.md @@ -1,7 +1,48 @@ -### Application build and update +Application build and update +---------------------------- -For application deployment we are using faster [Mina](https://github.com/mina-deploy/mina) -instead of Capistrano. +### Debian setup + +* [Debian build](/doc/debian_build_doc.md) + + +### Certificates setup + +* [Certificates setup](/doc/certificates.md) + + +### Production env setup + +For production you probably would like to create databases to your locale, example: + + create database registry_production owner registry encoding 'UTF-8' LC_COLLATE 'et_EE.utf8' LC_CTYPE 'et_EE.utf8' template template0; + +Deploy overview: (database schema should be loaded and seeds should be present) + + # at your local machine + git clone git@github.com:internetee/registry.git + cd registry + rbenv local 2.2.0 # more info about rbenv at debian doc + gem install mina + mina pr setup # one time, only creates missing directories + ssh registry + + # at your server + cd registry + cp current/config/application-example.yml shared/config/application.yml # and edit it + cp current/config/database-example.yml shared/config/database.yml # and edit it + + vi /etc/apache2/sites-enabled/registry.conf # add conf and all needed serts + vi /etc/apache2/sites-enabled/epp.conf # add epp conf, restart apache + exit + # at your local machine + mina pr deploy # this is command you use in every application code update + + + +### Deploy script setup + +We recommend [Mina](https://github.com/mina-deploy/mina) instead of Capistrano for deployment. All deploy code locates at config/deploy.rb file. @@ -68,3 +109,13 @@ General rake and mina tips: rake -T # list all rake commands rake -T db # list all database related commands mina -T # list all mina deploy commands + + +CRON +---- + +Crontab can be setup after deploy. Jobs can be viewed [here](/config/schedule.rb). + + mina pr cron:setup # to update the crontab. + mina pr cron:clear # to clear crontab. + diff --git a/doc/certificates.md b/doc/certificates.md index bf222a5e2..ea28a22f6 100644 --- a/doc/certificates.md +++ b/doc/certificates.md @@ -16,6 +16,16 @@ Private key and certificate must be packaged to pkcs12 and added to user browser ### Registry setup +Setup CA directory in shared directory: + + cd /home/registry/registry/shared + mkdir ca ca/certs ca/crl ca/newcerts ca/private ca/csrs + cd ca + chmod 700 private + touch index.txt + echo 1000 > serial + echo 1000 > crlnumber + Configure OpenSSL: sudo cp /etc/ssl/openssl.cnf /etc/ssl/openssl.cnf.bak @@ -53,17 +63,6 @@ Make sure the following options are in place: basicConstraints = CA:true # around line nr 240 keyUsage = cRLSign, keyCertSign # around line nr 245 -Setup CA directory in shared directory: - - cd /home/registry/registry/shared - mkdir ca - cd ca - mkdir certs crl newcerts private csrs - chmod 700 private - touch index.txt - echo 1000 > serial - echo 1000 > crlnumber - Generate the root key and remember your password, you need it later in application.yml: openssl genrsa -aes256 -out private/ca.key.pem 4096 @@ -90,10 +89,10 @@ Create certificate revocation list (prompts for pass phrase): Configure registry registry/shared/config/application.yml to match the CA settings: + crl_path: '/home/registry/registry/shared/ca/crl/crl.pem' ca_cert_path: '/home/registry/registry/shared/ca/certs/ca.crt.pem' - ca_key_path: '/home/registry/registry/shared/ca/private/ca.key.pem' + ca_key_path: '/home/registry/registry/shared/ca/private/ca.key.pem' ca_key_password: 'your-root-key-password' - crl_path: '/home/registry/registry/shared/ca/crl/crl.pem' ### Registry EPP setup @@ -162,6 +161,29 @@ Reload apache: sudo /etc/init.d/apache2 restart +### ApiUser browser setup + +In short: + +* Upload CSR file to api user at admin page /admin/api_users +* Sign it +* Generate p12 file and install into user browser + +#### Creating CSR file + + openssl genrsa -out private/api-user.key.pem 4096 + chmod 400 private/api-user.key.pem + openssl req -sha256 -new -days 3653 -key private/api-user.key.pem -out csrs/api-user.csr.pem + +Upload api-user.csr.pem file to api user at admin interface. +Sign it +Download CRT file and create p12 file. + + openssl pkcs12 -export -inkey private/api-user.key.pem -in certs/api-user.crt.pem -out pkcs/api_user.p12 + +Add api_user.p12 to your browser. + + Development env --------------- diff --git a/doc/epp/contact.md b/doc/epp/contact.md index 7bfe35468..db136c0db 100644 --- a/doc/epp/contact.md +++ b/doc/epp/contact.md @@ -1,6 +1,6 @@ ## Contact related functions -Please study official Cantact Mapping protocol: +Please study official Contact Mapping protocol: http://tools.ietf.org/html/rfc5733 More info at http://en.wikipedia.org/wiki/Extensible_Provisioning_Protocol @@ -13,6 +13,7 @@ Contact Mapping protocol short version: ----------------------- ------- ----------------- 1 1 Attribute: xmlns:contact="urn:ietf:params:xml:ns:contact-1.0" + 0-1 Contact id, optional, generated automatically if missing 1 Postal information container 1 Full name of the contact 0-1 Name of organization @@ -42,7 +43,7 @@ Contact Mapping protocol short version: ----------------------- ------- ----------------- 1 1 Attribute: xmlns:contact="urn:ietf:params:xml:ns:contact-1.0" - 1 contact id, required + 1 Contact id, required 1 Change container 1 Postal information container 0-1 Full name of the contact diff --git a/doc/testing.md b/doc/testing.md new file mode 100644 index 000000000..e7b56e0cb --- /dev/null +++ b/doc/testing.md @@ -0,0 +1,114 @@ +Testing +------- + +Setup test databases: + + RAILS_ENV=test rake db:all:setup + +Run basic test (no EPP tests): + + rake + + +Testing EPP +=========== + +In order to test EPP, you have to configure apache to handle EPP request correctly. + +### Apache site config + +First you should have mod_epp installed, please follow main README for doing it. + +Apache site config for autotest, add file to /etc/apache2/sites-enabled/epp-autotest.conf + +```apache + + Listen 701 + + SSLEngine on + SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL + SSLCertificateFile /etc/apache2/ssl/apache.crt + SSLCertificateKeyFile /etc/apache2/ssl/apache.key + + SSLVerifyClient optional_no_ca + + EPPEngine On + EPPCommandRoot /proxy/command + EPPSessionRoot /proxy/session + EPPErrorRoot /proxy/error + EPPRawFrame raw_frame + + ProxyPass /proxy/ http://localhost:8989/epp/ + + EPPAuthURI implicit + EPPReturncodeHeader X-EPP-Returncode + + +``` + + + +* Run all tests with temp server running automatically on port 8989: + + rake test + + +Manual debugging +================ + +### Apache mod_epp manual debugging + +Debugging Apache mod_epp without Registry app. + + sudo apt-get install apache2-dbg + +Includes htpasswd command to generate authentication files + + sudo apt-get install apache2-utils + +For manual debugging purposes, standalone CGI scripts can be used: +This needs a static greeting file, so you will have to make /var/www writable. + +```apache + + + Options ExecCGI + SetHandler cgi-script + + + Listen 1700 + + + EPPEngine On + EPPCommandRoot /cgi-bin/epp/command + EPPSessionRoot /cgi-bin/epp/session + EPPErrorRoot /cgi-bin/epp/error + + Alias /cgi-bin/epp/session/hello /var/www/html/epp/session-hello + + Alias /cgi-bin/epp/session/login /usr/lib/cgi-bin/epp/session-login + Alias /cgi-bin/epp/session/logout /usr/lib/cgi-bin/epp/session-logout + Alias /cgi-bin/epp/error/schema /usr/lib/cgi-bin/epp/error-schema + Alias /cgi-bin/epp/command/create /usr/lib/cgi-bin/epp/create + Alias /cgi-bin/epp/command/info /usr/lib/cgi-bin/epp/info + + EPPAuthURI /epp/auth/login + + AuthType Basic + AuthName "EPP" + AuthUserFile /etc/apache2/htpasswd + require valid-user + + + +``` + + sudo a2enmod cgi + sudo a2enmod authn_file # will be used for non implicit authentication URIs + sudo htpasswd -c /etc/apache2/htpasswd test + Type "test" when prompted + cd /usr/lib/cgi-bin + mkdir epp + +Copy the files from $mod_epp/examples/cgis to /usr/lib/cgi-bin/epp + diff --git a/spec/epp/contact_spec.rb b/spec/epp/contact_spec.rb index a025197c6..4690acfed 100644 --- a/spec/epp/contact_spec.rb +++ b/spec/epp/contact_spec.rb @@ -13,10 +13,8 @@ describe 'EPP Contact', epp: true do login_as :registrar1 - Contact.skip_callback(:create, :before, :generate_code) - Contact.skip_callback(:create, :before, :generate_auth_info) - @contact = Fabricate(:contact, registrar: @registrar1) + @legal_document = { legalDocument: { value: 'JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0Zp==', @@ -25,11 +23,6 @@ describe 'EPP Contact', epp: true do } end - after :all do - Contact.set_callback(:create, :before, :generate_code) - Contact.set_callback(:create, :before, :generate_auth_info) - end - context 'with valid user' do context 'create command' do def create_request(overwrites = {}) @@ -53,19 +46,19 @@ describe 'EPP Contact', epp: true do it 'fails if request xml is missing' do response = epp_plain_request(@epp_xml.create, :xml) response[:results][0][:msg].should == - 'Required parameter missing: create > create > postalInfo > name' + 'Required parameter missing: create > create > postalInfo > name [name]' response[:results][1][:msg].should == - 'Required parameter missing: create > create > postalInfo > addr > city' + 'Required parameter missing: create > create > postalInfo > addr > city [city]' response[:results][2][:msg].should == - 'Required parameter missing: create > create > postalInfo > addr > cc' + 'Required parameter missing: create > create > postalInfo > addr > cc [cc]' response[:results][3][:msg].should == - 'Required parameter missing: create > create > ident' + 'Required parameter missing: create > create > ident [ident]' response[:results][4][:msg].should == - 'Required parameter missing: create > create > voice' + 'Required parameter missing: create > create > voice [voice]' response[:results][5][:msg].should == - 'Required parameter missing: create > create > email' + 'Required parameter missing: create > create > email [email]' response[:results][6][:msg].should == - 'Required parameter missing: extension > extdata > legalDocument' + 'Required parameter missing: extension > extdata > legalDocument [legal_document]' response[:results][0][:result_code].should == '2003' response[:results][1][:result_code].should == '2003' @@ -133,6 +126,17 @@ describe 'EPP Contact', epp: true do # 5 seconds for what-ever weird lag reasons might happen cr_date.text.to_time.should be_within(5).of(Time.now) end + + it 'successfully saves custom code' do + response = create_request( + { id: { value: '12345' } } + ) + + response[:msg].should == 'Command completed successfully' + response[:result_code].should == '1000' + + Contact.last.code.should == 'registrar1:12345' + end end context 'update command' do @@ -140,11 +144,9 @@ describe 'EPP Contact', epp: true do @contact = Fabricate( :contact, - # created_by_id: 1, registrar: @registrar1, email: 'not_updated@test.test', - code: 'sh8013', - auth_info: 'password' + code: 'sh8013' ) end @@ -177,13 +179,13 @@ describe 'EPP Contact', epp: true do 'Required parameter missing: add, rem or chg' response[:results][0][:result_code].should == '2003' response[:results][1][:msg].should == - 'Required parameter missing: update > update > id' + 'Required parameter missing: update > update > id [id]' response[:results][1][:result_code].should == '2003' response[:results][2][:msg].should == - 'Required parameter missing: update > update > authInfo > pw' + 'Required parameter missing: update > update > authInfo > pw [pw]' response[:results][2][:result_code].should == '2003' response[:results][3][:msg].should == - 'Required parameter missing: extension > extdata > legalDocument' + 'Required parameter missing: extension > extdata > legalDocument [legal_document]' response[:results][3][:result_code].should == '2003' response[:results].count.should == 4 end @@ -221,11 +223,25 @@ describe 'EPP Contact', epp: true do } }) - response[:results][0][:msg].should == 'Phone nr is invalid' + response[:results][0][:msg].should == 'Phone nr is invalid [phone]' response[:results][0][:result_code].should == '2005' - response[:results][1][:msg].should == 'Email is invalid' + response[:results][1][:msg].should == 'Email is invalid [email]' response[:results][1][:result_code].should == '2005' end + + it 'should not update code with custom string' do + response = update_request( + id: { value: 'sh8013' }, + chg: { + id: { value: 'notpossibletoupdate' } + } + ) + + response[:msg].should == 'Object does not exist' + response[:result_code].should == '2303' + + @contact.reload.code.should == 'sh8013' + end end context 'delete command' do @@ -246,13 +262,13 @@ describe 'EPP Contact', epp: true do response = epp_plain_request(@epp_xml.delete, :xml) response[:results][0][:msg].should == - 'Required parameter missing: delete > delete > id' + 'Required parameter missing: delete > delete > id [id]' response[:results][0][:result_code].should == '2003' response[:results][1][:msg].should == - 'Required parameter missing: delete > delete > authInfo > pw' + 'Required parameter missing: delete > delete > authInfo > pw [pw]' response[:results][1][:result_code].should == '2003' response[:results][2][:msg].should == - 'Required parameter missing: extension > extdata > legalDocument' + 'Required parameter missing: extension > extdata > legalDocument [legal_document]' response[:results][2][:result_code].should == '2003' response[:results].count.should == 3 end @@ -278,7 +294,7 @@ describe 'EPP Contact', epp: true do @domain.owner_contact.address.present?.should == true response = delete_request - response[:msg].should == 'Object association prohibits operation' + response[:msg].should == 'Object association prohibits operation [domains]' response[:result_code].should == '2305' response[:results].count.should == 1 @@ -308,7 +324,7 @@ describe 'EPP Contact', epp: true do it 'fails if request is invalid' do response = epp_plain_request(@epp_xml.check, :xml) - response[:results][0][:msg].should == 'Required parameter missing: check > check > id' + response[:results][0][:msg].should == 'Required parameter missing: check > check > id [id]' response[:results][0][:result_code].should == '2003' response[:results].count.should == 1 end @@ -343,7 +359,7 @@ describe 'EPP Contact', epp: true do it 'fails if request invalid' do response = epp_plain_request(@epp_xml.info, :xml) response[:results][0][:msg].should == - 'Required parameter missing: info > info > id' + 'Required parameter missing: info > info > id [id]' response[:results][0][:result_code].should == '2003' response[:results].count.should == 1 end diff --git a/spec/epp/domain_spec.rb b/spec/epp/domain_spec.rb index cf49a0987..1b03e2487 100644 --- a/spec/epp/domain_spec.rb +++ b/spec/epp/domain_spec.rb @@ -11,8 +11,6 @@ describe 'EPP Domain', epp: true do login_as :registrar1 - Contact.skip_callback(:create, :before, :generate_code) - Fabricate(:contact, code: 'citizen_1234') Fabricate(:contact, code: 'sh8013') Fabricate(:contact, code: 'sh801333') @@ -61,16 +59,20 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:results][0][:result_code].should == '2003' - response[:results][0][:msg].should == 'Required parameter missing: create > create > ns' + response[:results][0][:msg].should == + 'Required parameter missing: create > create > ns [ns]' response[:results][1][:result_code].should == '2003' - response[:results][1][:msg].should == 'Required parameter missing: create > create > registrant' + response[:results][1][:msg].should == + 'Required parameter missing: create > create > registrant [registrant]' response[:results][2][:result_code].should == '2003' - response[:results][2][:msg].should == 'Required parameter missing: create > create > ns > hostAttr' + response[:results][2][:msg].should == + 'Required parameter missing: create > create > ns > hostAttr [host_attr]' response[:results][3][:result_code].should == '2003' - response[:results][3][:msg].should == 'Required parameter missing: extension > extdata > legalDocument' + response[:results][3][:msg].should == + 'Required parameter missing: extension > extdata > legalDocument [legal_document]' end context 'with citizen as an owner' do @@ -169,7 +171,7 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:result_code].should == '2306' - response[:msg].should == 'IPv4 is missing' + response[:msg].should == 'IPv4 is missing [ipv4]' end # it 'does not create duplicate domain' do @@ -191,7 +193,7 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:result_code].should == '2302' - response[:msg].should == 'Domain name is reserved or restricted' + response[:msg].should == 'Domain name is reserved or restricted [name_dirty]' response[:clTRID].should == 'ABC-12345' end @@ -200,7 +202,8 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:results][0][:result_code].should == '2003' - response[:results][0][:msg].should == 'Required parameter missing: create > create > registrant' + response[:results][0][:msg].should == + 'Required parameter missing: create > create > registrant [registrant]' end it 'does not create domain without nameservers' do @@ -208,11 +211,11 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:results][0][:msg].should == - 'Required parameter missing: create > create > ns' + 'Required parameter missing: create > create > ns [ns]' response[:results][0][:result_code].should == '2003' response[:results][1][:msg].should == - 'Required parameter missing: create > create > ns > hostAttr' + 'Required parameter missing: create > create > ns > hostAttr [host_attr]' response[:results][1][:result_code].should == '2003' response[:results].count.should == 2 @@ -234,7 +237,7 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:result_code].should == '2004' - response[:msg].should == 'Nameservers count must be between 2-11' + response[:msg].should == 'Nameservers count must be between 2-11 [nameservers]' end it 'returns error when invalid nameservers are present' do @@ -254,8 +257,8 @@ describe 'EPP Domain', epp: true do }) response = epp_plain_request(xml, :xml) + response[:msg].should == 'Hostname is invalid [hostname]' response[:result_code].should == '2005' - response[:msg].should == 'Hostname is invalid' end it 'checks hostAttr presence' do @@ -271,8 +274,8 @@ describe 'EPP Domain', epp: true do }) response = epp_plain_request(xml, :xml) + response[:msg].should == 'Required parameter missing: create > create > ns > hostAttr [host_attr]' response[:result_code].should == '2003' - response[:msg].should == 'Required parameter missing: create > create > ns > hostAttr' end it 'creates domain with nameservers with ips' do @@ -288,10 +291,10 @@ describe 'EPP Domain', epp: true do nameserver_count = Nameserver.count response = epp_plain_request(domain_create_with_invalid_ns_ip_xml, :xml) response[:results][0][:result_code].should == '2005' - response[:results][0][:msg].should == 'IPv4 is invalid' + response[:results][0][:msg].should == 'IPv4 is invalid [ipv4]' response[:results][0][:value].should == '192.0.2.2.invalid' response[:results][1][:result_code].should == '2005' - response[:results][1][:msg].should == 'IPv6 is invalid' + response[:results][1][:msg].should == 'IPv6 is invalid [ipv6]' response[:results][1][:value].should == 'INVALID_IPV6' # ensure nothing gets saved to db: Domain.count.should == domain_count @@ -314,7 +317,7 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:results][0][:result_code].should == '2004' - response[:results][0][:msg].should == 'Period must add up to 1, 2 or 3 years' + response[:results][0][:msg].should == 'Period must add up to 1, 2 or 3 years [period]' response[:results][0][:value].should == '367' end @@ -399,24 +402,25 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) - response[:results][0][:msg].should == 'Valid algorithms are: 3, 5, 6, 7, 8, 252, 253, 254, 255' + response[:results][0][:msg].should == + 'Valid algorithms are: 3, 5, 6, 7, 8, 252, 253, 254, 255 [alg]' response[:results][0][:value].should == '9' - response[:results][1][:msg].should == 'Valid protocols are: 3' + response[:results][1][:msg].should == 'Valid protocols are: 3 [protocol]' response[:results][1][:value].should == '4' - response[:results][2][:msg].should == 'Valid flags are: 0, 256, 257' + response[:results][2][:msg].should == 'Valid flags are: 0, 256, 257 [flags]' response[:results][2][:value].should == '250' - response[:results][3][:msg].should == 'Valid algorithms are: 3, 5, 6, 7, 8, 252, 253, 254, 255' + response[:results][3][:msg].should == 'Valid algorithms are: 3, 5, 6, 7, 8, 252, 253, 254, 255 [alg]' response[:results][3][:value].should == '10' - response[:results][4][:msg].should == 'Valid flags are: 0, 256, 257' + response[:results][4][:msg].should == 'Valid flags are: 0, 256, 257 [flags]' response[:results][4][:value].should == '1' - response[:results][5][:msg].should == 'Public key is missing' + response[:results][5][:msg].should == 'Public key is missing [public_key]' - response[:results][6][:msg].should == 'Valid protocols are: 3' + response[:results][6][:msg].should == 'Valid protocols are: 3 [protocol]' response[:results][6][:value].should == '5' end @@ -443,7 +447,7 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:result_code].should == '2302' - response[:msg].should == 'Public key already exists' + response[:msg].should == 'Public key already exists [public_key]' response[:results][0][:value].should == '700b97b591ed27ec2590d19f06f88bba700b97b591ed27ec2590d19f' end @@ -472,7 +476,7 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:result_code].should == '2004' - response[:msg].should == 'DNS keys count must be between 0-1' + response[:msg].should == 'DNS keys count must be between 0-1 [dnskeys]' create_settings end @@ -669,7 +673,7 @@ describe 'EPP Domain', epp: true do }) response = epp_plain_request(xml, :xml) - response[:msg].should == 'Admin contacts count must be between 1-10' + response[:msg].should == 'Admin contacts count must be between 1-10 [admin_contacts]' response[:result_code].should == '2004' response[:clTRID].should == 'ABC-12345' @@ -861,7 +865,8 @@ describe 'EPP Domain', epp: true do login_as :registrar2 do response = epp_plain_request(xml, :xml) response[:result_code].should == '2003' - response[:msg].should == 'Required parameter missing: extension > extdata > legalDocument' + response[:msg].should == + 'Required parameter missing: extension > extdata > legalDocument [legal_document]' end end @@ -978,7 +983,7 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:result_code].should == '2201' - response[:msg].should == 'Authorization error' + response[:msg].should == 'Authorization error [auth_info]' end it 'ignores transfer when owner registrar requests transfer' do @@ -1025,7 +1030,7 @@ describe 'EPP Domain', epp: true do epp_plain_request(xml, :xml) # transfer domain response = epp_plain_request(xml, :xml) # attempt second transfer response[:result_code].should == '2201' - response[:msg].should == 'Authorization error' + response[:msg].should == 'Authorization error [auth_info]' end end @@ -1128,27 +1133,27 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:results][0][:result_code].should == '2302' - response[:results][0][:msg].should == 'Nameserver already exists on this domain' + response[:results][0][:msg].should == 'Nameserver already exists on this domain [hostname]' response[:results][0][:value].should == 'ns1.example.com' response[:results][1][:result_code].should == '2302' - response[:results][1][:msg].should == 'Nameserver already exists on this domain' + response[:results][1][:msg].should == 'Nameserver already exists on this domain [hostname]' response[:results][1][:value].should == 'ns2.example.com' response[:results][2][:result_code].should == '2302' - response[:results][2][:msg].should == 'Contact already exists on this domain' + response[:results][2][:msg].should == 'Contact already exists on this domain [contact_code_cache]' response[:results][2][:value].should == 'mak21' - response[:results][3][:msg].should == 'Status already exists on this domain' + response[:results][3][:msg].should == 'Status already exists on this domain [value]' response[:results][3][:value].should == 'clientHold' - response[:results][4][:msg].should == 'Status already exists on this domain' + response[:results][4][:msg].should == 'Status already exists on this domain [value]' response[:results][4][:value].should == 'clientUpdateProhibited' - response[:results][5][:msg].should == 'Public key already exists' + response[:results][5][:msg].should == 'Public key already exists [public_key]' response[:results][5][:value].should == '700b97b591ed27ec2590d19f06f88bba700b97b591ed27ec2590d19f' - response[:results][6][:msg].should == 'Public key already exists' + response[:results][6][:msg].should == 'Public key already exists [public_key]' response[:results][6][:value].should == '841936717ae427ace63c28d04918569a841936717ae427ace63c28d0' d.domain_statuses.count.should == 2 @@ -1300,11 +1305,11 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:results][0][:result_code].should == '2302' - response[:results][0][:msg].should == 'Nameserver already exists on this domain' + response[:results][0][:msg].should == 'Nameserver already exists on this domain [hostname]' response[:results][0][:value].should == n.hostname response[:results][1][:result_code].should == '2302' - response[:results][1][:msg].should == 'Contact already exists on this domain' + response[:results][1][:msg].should == 'Contact already exists on this domain [contact_code_cache]' response[:results][1][:value].should == c.code end @@ -1317,7 +1322,8 @@ describe 'EPP Domain', epp: true do } response = epp_plain_request(domain_update_xml(xml_params), :xml) - response[:results][0][:msg].should == 'Required parameter missing: extension > extdata > legalDocument' + response[:results][0][:msg].should == + 'Required parameter missing: extension > extdata > legalDocument [legal_document]' response[:results][0][:result_code].should == '2003' end @@ -1374,7 +1380,7 @@ describe 'EPP Domain', epp: true do response = epp_plain_request(xml, :xml) response[:results][0][:result_code].should == '2004' - response[:results][0][:msg].should == 'Period must add up to 1, 2 or 3 years' + response[:results][0][:msg].should == 'Period must add up to 1, 2 or 3 years [period]' response[:results][0][:value].should == '4' end @@ -1526,7 +1532,8 @@ describe 'EPP Domain', epp: true do it 'does not delete domain without legal document' do response = epp_plain_request(@epp_xml.domain.delete(name: { value: 'example.ee' }), :xml) response[:result_code].should == '2003' - response[:msg].should == 'Required parameter missing: extension > extdata > legalDocument' + response[:msg].should == + 'Required parameter missing: extension > extdata > legalDocument [legal_document]' end ### CHECK ### diff --git a/spec/epp/keyrelay_spec.rb b/spec/epp/keyrelay_spec.rb index 7d513391b..731873d08 100644 --- a/spec/epp/keyrelay_spec.rb +++ b/spec/epp/keyrelay_spec.rb @@ -64,7 +64,7 @@ describe 'EPP Keyrelay', epp: true do }) response = epp_plain_request(xml, :xml) - response[:msg].should == 'Required parameter missing: keyrelay > keyData > flags' + response[:msg].should == 'Required parameter missing: keyrelay > keyData > flags [flags]' @registrar2.messages.queued.count.should == msg_count end diff --git a/spec/epp/session_spec.rb b/spec/epp/session_spec.rb index 2da903652..e0e8afae9 100644 --- a/spec/epp/session_spec.rb +++ b/spec/epp/session_spec.rb @@ -35,6 +35,7 @@ describe 'EPP Session', epp: true do inactive = @epp_xml.session.login(clID: { value: 'inactive-user' }, pw: { value: 'ghyt9e4fu' }) response = epp_plain_request(inactive, :xml) + response[:msg].should == 'Authentication error; server closing connection' response[:result_code].should == '2501' end diff --git a/spec/fabricators/contact_fabricator.rb b/spec/fabricators/contact_fabricator.rb index 0462f7a61..45c4db75e 100644 --- a/spec/fabricators/contact_fabricator.rb +++ b/spec/fabricators/contact_fabricator.rb @@ -1,13 +1,16 @@ Fabricator(:contact) do code { "sh#{Faker::Number.number(8)}" } + auth_info 'password' name { sequence(:name) { |i| "#{Faker::Name.name}#{i}" } } phone '+372.12345678' email Faker::Internet.email ident '37605030299' ident_type 'priv' ident_country_code 'EE' - auth_info 'ccds4324pok' address registrar { Fabricate(:registrar, name: Faker::Company.name, reg_no: Faker::Company.duns_number) } disclosure { Fabricate(:contact_disclosure) } + # rubocop: disable Style/SymbolProc + after_validation { |c| c.disable_generate_auth_info! } + # rubocop: enamble Style/SymbolProc end diff --git a/spec/models/contact_spec.rb b/spec/models/contact_spec.rb index d605e9781..dbf7bc3dc 100644 --- a/spec/models/contact_spec.rb +++ b/spec/models/contact_spec.rb @@ -91,6 +91,12 @@ describe Contact do it 'should not have any versions' do @contact.versions.should == [] end + + it 'should not accept long code' do + @contact.code = 'verylongcode' * 100 + @contact.valid? + @contact.errors[:code].should == ['is too long (maximum is 100 characters)'] + end end context 'with valid attributes' do @@ -130,6 +136,17 @@ describe Contact do @contact.errors.full_messages.should match_array([]) end + it 'should not accept new custom code' do + old_code = @contact.code + @contact.code = 'CID:REG1:12345' + @contact.save.should == true + @contact.code.should == old_code + end + + it 'should have static password' do + @contact.auth_info.should == 'password' + end + context 'as birthday' do before :all do @contact.ident_type = 'birthday' @@ -182,20 +199,56 @@ describe Contact do end context 'after create' do - it 'should generate a new code and password' do + it 'should not generate a new code when code is present' do + @contact = Fabricate.build(:contact, code: '123asd', auth_info: 'qwe321') + @contact.code.should == '123asd' + @contact.save.should == true + @contact.code.should == '123asd' + end + + it 'should generate a new password' do @contact = Fabricate.build(:contact, code: '123asd', auth_info: 'qwe321') - @contact.code.should == '123asd' @contact.auth_info.should == 'qwe321' - @contact.save! - @contact.code.should_not == '123asd' + @contact.save.should == true @contact.auth_info.should_not == 'qwe321' end + + it 'should not allow same code' do + @double_contact = Fabricate.build(:contact, code: @contact.code) + @double_contact.valid? + @double_contact.errors.full_messages.should == ["Code Contact id already exists"] + end + + it 'should allow supported code format' do + @contact = Fabricate.build(:contact, code: 'CID:REG1:12345') + @contact.valid? + @contact.errors.full_messages.should == [] + end + + it 'should not allow unsupported characters in code' do + @contact = Fabricate.build(:contact, code: 'unsupported!ÄÖÜ~?') + @contact.valid? + @contact.errors.full_messages.should == ['Code is invalid'] + end + + it 'should generate code if empty code is given' do + @contact = Fabricate(:contact, code: '') + @contact.code.should_not == '' + end + + it 'should not allow empty spaces as code' do + @contact = Fabricate.build(:contact, code: ' ') + @contact.valid? + @contact.errors.full_messages.should == ['Code is invalid'] + end end context 'after update' do before :all do - @contact.code = '123asd' - @contact.auth_info = 'qwe321' + @contact = Fabricate.build(:contact, code: '123asd', auth_info: 'qwe321') + @contact.save + @contact.code.should == '123asd' + @auth_info = @contact.auth_info end it 'should not generate new code' do @@ -205,7 +258,7 @@ describe Contact do it 'should not generate new auth_info' do @contact.update_attributes(name: 'fvrsgbqevciherot23') - @contact.auth_info.should == 'qwe321' + @contact.auth_info.should == @auth_info end end end diff --git a/spec/models/registrar_spec.rb b/spec/models/registrar_spec.rb index 7271a307d..4c92e5f66 100644 --- a/spec/models/registrar_spec.rb +++ b/spec/models/registrar_spec.rb @@ -28,6 +28,10 @@ describe Registrar do @registrar.errors[:email].should == ['is invalid'] @registrar.errors[:billing_email].should == ['is invalid'] end + + it 'should not have valid code' do + @registrar.code.should == nil + end end context 'with valid attributes' do @@ -59,5 +63,26 @@ describe Registrar do it 'should return full address' do @registrar.address.should == 'Street 999, Town, County, Postal' end + + it 'should have code' do + @registrar.code.should =~ /registrar/ + end + + it 'should not be able to change code' do + @registrar.code = 'not-updated' + @registrar.code.should =~ /registrar/ + end + + it 'should automatically add next code if original is taken' do + @registrar = Fabricate(:registrar, name: 'uniq') + @registrar.name = 'New name' + @registrar.code.should == 'uniq' + @registrar.save + + @new_registrar = Fabricate.build(:registrar, name: 'uniq') + @new_registrar.valid? + @new_registrar.errors.full_messages.should == [] + @new_registrar.code.should == 'uniq1' + end end end