Merge branch 'master' into domains-nested-refactor

Conflicts:
	config/locales/en.yml
This commit is contained in:
Martin Lensment 2015-03-06 10:26:38 +02:00
commit 08fb2966d4
93 changed files with 2356 additions and 1678 deletions

6
.gitignore vendored
View file

@ -10,10 +10,11 @@ capybara-*.html
/spec/tmp /spec/tmp
**.orig **.orig
config/initializers/secret_token.rb config/initializers/secret_token.rb
config/application.yml
config/secrets.yml config/secrets.yml
config/database.yml config/database.yml
/export /export
/ca
todo
## Environment normalisation: ## Environment normalisation:
/.bundle /.bundle
@ -24,3 +25,6 @@ config/database.yml
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc .rvmrc
# Ignore application configuration
/config/application.yml

View file

@ -77,3 +77,7 @@ Style/AsciiComments:
# because NerdCommenter honors commented code intentions # because NerdCommenter honors commented code intentions
Style/CommentIndentation: Style/CommentIndentation:
Enabled: false Enabled: false
# It did not alayws suggested good format
Style/AlignParameters:
Enabled: false

27
.travis.yml Normal file
View file

@ -0,0 +1,27 @@
language: ruby
rvm:
- 2.2
- ruby-head
env:
- DB=postgresql
sudo: false
before_install:
- gem install bundler
- "rm ${BUNDLE_GEMFILE}.lock"
before_script:
- psql -c 'create database registry_test;' -U postgres
- psql -c 'create database registry_whois_test;' -U postgres
- psql -c 'create database registry_api_log_test;' -U postgres
- bundle update
- cp config/application-example.yml config/application.yml
- cp config/secrets-example.yml config/secrets.yml
- cp config/database-travis.yml config/database.yml
- RAILS_ENV=test bundle exec rake db:all:schema:load
- RAILS_ENV=test bundle exec rake db:seed
script:
- RAILS_ENV=test bundle exec rake
cache: bundler
services:
- postgresql
addons:
postgresql: "9.3"

View file

@ -1,93 +1,11 @@
12.02.2015 27.02.2015
Go to registry shared folder and setup CA directory tree: * Simplified config/application-example.yml,
``` now system will check if all required settings are present in application.yml
mkdir ca
cd ca
mkdir certs crl newcerts private
chmod 700 private
touch index.txt
echo 1000 > serial
```
Generate the root key (prompts for pass phrase): 19.02.2015
```
openssl genrsa -aes256 -out private/ca.key.pem 4096
```
Configure OpenSSL: * Cetrificate only enabled, please setup certificates following doc/certificate.md document.
```
sudo su -
cd /etc/ssl/
cp openssl.cnf openssl.cnf.bak
nano openssl.cnf
exit
```
Make sure the following options are in place:
```
[ CA_default ]
# Where everything is kept
dir = /home/registry/registry/shared/ca
[ usr_cert ]
# These extensions are added when 'ca' signs a request.
basicConstraints=CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
[ v3_ca ]
# Extensions for a typical CA
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = CA:true
keyUsage = cRLSign, keyCertSign
[ policy_match ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = optional
emailAddress = optional
```
Issue the root certificate (prompts for additional data):
```
openssl req -new -x509 -days 3650 -key private/ca.key.pem -sha256 -extensions v3_ca -out certs/ca.cert.pem
chmod 444 certs/ca.cert.pem
```
Configure EPP virtual host:
```
sudo nano /etc/apache2/sites-enabled/epp.conf
```
Replace this line:
```
SSLVerifyClient optional_no_ca
```
With these lines:
```
SSLVerifyClient require
SSLVerifyDepth 1
SSLCACertificateFile /home/registry/registry/shared/ca/certs/ca.cert.pem
```
Reload apache:
```
sudo /etc/init.d/apache2 reload
```
Configure application.yml to match the CA settings:
```
ca_cert_path: '/home/registry/registry/shared/ca/certs/ca.cert.pem'
ca_key_path: '/home/registry/registry/shared/ca/private/ca.key.pem'
ca_key_password: 'registryalpha'
```
20.01.2015 20.01.2015

11
Gemfile
View file

@ -5,10 +5,16 @@ gem 'rails', '4.2.0'
gem 'iso8601', '~> 0.8.2' # for dates and times gem 'iso8601', '~> 0.8.2' # for dates and times
gem 'hashie_rails', '~> 0.0.1' gem 'hashie_rails', '~> 0.0.1'
# load env
gem 'figaro', '~> 1.1.0'
# model related # model related
gem 'pg', '~> 0.18.0' gem 'pg', '~> 0.18.0'
gem 'ransack', '~> 1.5.1' # for searching gem 'ransack', '~> 1.5.1' # for searching
gem 'paper_trail', '~> 4.0.0.beta2' # archiving # with polymorphic fix
gem 'paper_trail',
github: 'airblade/paper_trail',
ref: 'a453811226ec4ea59753ba6b827e390ced2fc140' # '~> 4.0.0.beta2' # archiving
gem 'rails-settings-cached', '~> 0.4.1' # for settings gem 'rails-settings-cached', '~> 0.4.1' # for settings
gem 'delayed_job_active_record', '~> 4.0.3' # delayed job gem 'delayed_job_active_record', '~> 4.0.3' # delayed job
@ -110,4 +116,7 @@ group :development, :test do
# dev tools # dev tools
gem 'unicorn' gem 'unicorn'
# for travis
gem 'rake'
end end

View file

@ -1,3 +1,13 @@
GIT
remote: git://github.com/airblade/paper_trail.git
revision: a453811226ec4ea59753ba6b827e390ced2fc140
ref: a453811226ec4ea59753ba6b827e390ced2fc140
specs:
paper_trail (4.0.0.beta3)
activerecord (>= 3.0, < 6.0)
activesupport (>= 3.0, < 6.0)
request_store (~> 1.1.0)
GIT GIT
remote: git://github.com/haml/html2haml.git remote: git://github.com/haml/html2haml.git
revision: 6984f50bdbbd6291535027726a5697f28778ee8d revision: 6984f50bdbbd6291535027726a5697f28778ee8d
@ -142,6 +152,8 @@ GEM
i18n (~> 0.5) i18n (~> 0.5)
fastercsv (1.5.5) fastercsv (1.5.5)
ffi (1.9.6) ffi (1.9.6)
figaro (1.1.0)
thor (~> 0.14)
flay (2.4.0) flay (2.4.0)
ruby_parser (~> 3.0) ruby_parser (~> 3.0)
sexp_processor (~> 4.0) sexp_processor (~> 4.0)
@ -235,9 +247,6 @@ GEM
nprogress-rails (0.1.6.5) nprogress-rails (0.1.6.5)
open4 (1.3.4) open4 (1.3.4)
orm_adapter (0.5.0) orm_adapter (0.5.0)
paper_trail (4.0.0.beta2)
activerecord (>= 3.0, < 6.0)
activesupport (>= 3.0, < 6.0)
parser (2.2.0.2) parser (2.2.0.2)
ast (>= 1.1, < 3.0) ast (>= 1.1, < 3.0)
pg (0.18.1) pg (0.18.1)
@ -309,6 +318,7 @@ GEM
ruby_parser (~> 3.3) ruby_parser (~> 3.3)
sexp_processor sexp_processor
ref (1.0.5) ref (1.0.5)
request_store (1.1.0)
responders (2.0.2) responders (2.0.2)
railties (>= 4.2.0.alpha, < 5) railties (>= 4.2.0.alpha, < 5)
rspec (3.0.0) rspec (3.0.0)
@ -451,6 +461,7 @@ DEPENDENCIES
epp-xml (~> 0.10.4) epp-xml (~> 0.10.4)
fabrication (~> 2.12.2) fabrication (~> 2.12.2)
faker (~> 1.3.0) faker (~> 1.3.0)
figaro (~> 1.1.0)
grape (~> 0.10.1) grape (~> 0.10.1)
guard (~> 2.6.1) guard (~> 2.6.1)
guard-rails (~> 0.7.0) guard-rails (~> 0.7.0)
@ -469,7 +480,7 @@ DEPENDENCIES
newrelic_rpm (~> 3.9.9.275) newrelic_rpm (~> 3.9.9.275)
nokogiri (~> 1.6.2.1) nokogiri (~> 1.6.2.1)
nprogress-rails (~> 0.1.6.5) nprogress-rails (~> 0.1.6.5)
paper_trail (~> 4.0.0.beta2) paper_trail!
pg (~> 0.18.0) pg (~> 0.18.0)
phantomjs (~> 1.9.7.1) phantomjs (~> 1.9.7.1)
phantomjs-binaries (~> 1.9.2.4) phantomjs-binaries (~> 1.9.2.4)
@ -478,6 +489,7 @@ DEPENDENCIES
railroady (~> 1.3.0) railroady (~> 1.3.0)
rails (= 4.2.0) rails (= 4.2.0)
rails-settings-cached (~> 0.4.1) rails-settings-cached (~> 0.4.1)
rake
ransack (~> 1.5.1) ransack (~> 1.5.1)
rspec-rails (~> 3.0.2) rspec-rails (~> 3.0.2)
rubocop (~> 0.26.1) rubocop (~> 0.26.1)

View file

@ -3,11 +3,11 @@ group :red_green_refactor, halt_on_fail: true do
# be sure you have apache2 configured to # be sure you have apache2 configured to
# accept EPP request on port 701, what proxy to 8989. # accept EPP request on port 701, what proxy to 8989.
# port and environment is just for correct notification, all is overwritten by CLI # 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' do
# guard :rails, port: 8989, environment: 'test', CLI: 'RAILS_ENV=test unicorn -p 8989' do # # guard :rails, port: 8989, environment: 'test', CLI: 'RAILS_ENV=test unicorn -p 8989' do
watch('Gemfile.lock') # watch('Gemfile.lock')
watch(%r{^(config|lib)/.*}) # watch(%r{^(config|lib)/.*})
end # end
guard :rspec, cmd: 'spring rspec', notification: false do guard :rspec, cmd: 'spring rspec', notification: false do
watch(%r{^spec/.+_spec\.rb$}) watch(%r{^spec/.+_spec\.rb$})
@ -18,6 +18,8 @@ group :red_green_refactor, halt_on_fail: true do
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" } watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] } watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
watch(%r{^app/controllers/epp/(.+)_(controller)\.rb$}) { |m| ["spec/epp/#{m[1].sub(/s$/,'')}_spec.rb"] }
watch(%r{^app/models/epp/(.+)\.rb$}) { |m| "spec/epp/#{m[1]}_spec.rb" }
watch(%r{^spec/support/(.+)\.rb$}) { "spec" } watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
watch('config/routes.rb') { "spec/routing" } watch('config/routes.rb') { "spec/routing" }
watch('app/controllers/application_controller.rb') { "spec/controllers" } watch('app/controllers/application_controller.rb') { "spec/controllers" }

145
README.md
View file

@ -23,7 +23,7 @@ Installation
### Registry app ### 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: Manual demo install and database setup:
@ -32,44 +32,11 @@ Manual demo install and database setup:
cd demo-registry cd demo-registry
rbenv local 2.2.0 rbenv local 2.2.0
bundle 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/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 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) ### Apache with patched mod_epp (Debian 7/Ubuntu 14.04 LTS)
sudo apt-get install apache2 sudo apt-get install apache2
@ -152,7 +119,12 @@ Be sure to update paths to match your system configuration.
SSLVerifyClient require SSLVerifyClient require
SSLVerifyDepth 1 SSLVerifyDepth 1
SSLCACertificateFile /home/registry/registry/shared/ca/certs/ca.cert.pem SSLCACertificateFile /home/registry/registry/shared/ca/certs/ca.crt.pem
SSLCARevocationFile /home/registry/registry/shared/ca/crl/crl.pem
# Uncomment this when upgrading to apache 2.4:
# SSLCARevocationCheck chain
RequestHeader set SSL_CLIENT_S_DN_CN "%{SSL_CLIENT_S_DN_CN}s"
EPPEngine On EPPEngine On
EPPCommandRoot /proxy/command EPPCommandRoot /proxy/command
@ -182,6 +154,21 @@ All registry demo data can be found at:
Initially you can use two type of users: admin users and EPP users. 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 ### EPP web client
Please follow EPP web client readme: Please follow EPP web client readme:
@ -196,85 +183,7 @@ Please follow WHOIS server readme:
https://github.com/internetee/whois https://github.com/internetee/whois
Deployment ## Code Status
----------
* [Debian build](/doc/debian_build_doc.md) Alpha release status, only model tests:
* [Application build and update](/doc/application_build_doc.md) [![Build Status](https://travis-ci.org/domify/registry.svg?branch=master)](https://travis-ci.org/domify/registry)
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
<IfModule mod_epp.c>
<Directory "/usr/lib/cgi-bin/epp">
Options ExecCGI
SetHandler cgi-script
</Directory>
Listen 1700
<VirtualHost *: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
<Location /epp/auth>
AuthType Basic
AuthName "EPP"
AuthUserFile /etc/apache2/htpasswd
require valid-user
</Location>
</VirtualHost>
</IfModule>
```
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

View file

@ -12,10 +12,7 @@ class Admin::ApiUsersController < AdminController
end end
def create def create
app = api_user_params @api_user = ApiUser.new(api_user_params)
app[:csr] = params[:api_user][:csr].open.read if params[:api_user][:csr]
@api_user = ApiUser.new(app)
if @api_user.save if @api_user.save
flash[:notice] = I18n.t('record_created') flash[:notice] = I18n.t('record_created')
@ -31,10 +28,7 @@ class Admin::ApiUsersController < AdminController
def edit; end def edit; end
def update def update
app = api_user_params if @api_user.update(api_user_params)
app[:csr] = params[:api_user][:csr].open.read if params[:api_user][:csr]
if @api_user.update(app)
flash[:notice] = I18n.t('record_updated') flash[:notice] = I18n.t('record_updated')
redirect_to [:admin, @api_user] redirect_to [:admin, @api_user]
else else
@ -53,14 +47,6 @@ class Admin::ApiUsersController < AdminController
end end
end end
def download_csr
send_data @api_user.csr, filename: "#{@api_user.username}.csr.pem"
end
def download_crt
send_data @api_user.crt, filename: "#{@api_user.username}.crt.pem"
end
private private
def set_api_user def set_api_user
@ -68,6 +54,6 @@ class Admin::ApiUsersController < AdminController
end end
def api_user_params def api_user_params
params.require(:api_user).permit(:username, :password, :csr, :active, :registrar_id, :registrar_typeahead) params.require(:api_user).permit(:username, :password, :active, :registrar_id, :registrar_typeahead)
end end
end end

View file

@ -0,0 +1,68 @@
class Admin::CertificatesController < AdminController
load_and_authorize_resource
before_action :set_certificate, :set_api_user, only: [:sign, :show, :download_csr, :download_crt, :revoke]
def show
@csr = OpenSSL::X509::Request.new(@certificate.csr) if @certificate.csr
@crt = OpenSSL::X509::Certificate.new(@certificate.crt) if @certificate.crt
end
def new
set_api_user
@certificate = Certificate.new
end
def create
@api_user = ApiUser.find(params[:api_user_id])
csr = certificate_params[:csr].open.read if certificate_params[:csr]
@certificate = @api_user.certificates.build(csr: csr)
if @api_user.save
flash[:notice] = I18n.t('record_created')
redirect_to [:admin, @api_user, @certificate]
else
flash.now[:alert] = I18n.t('failed_to_create_record')
render 'new'
end
end
def sign
if @certificate.sign!
flash[:notice] = I18n.t('record_updated')
else
flash[:alert] = I18n.t('failed_to_update_record')
end
redirect_to [:admin, @api_user, @certificate]
end
def revoke
if @certificate.revoke!
flash[:notice] = I18n.t('record_updated')
else
flash[:alert] = I18n.t('failed_to_update_record')
end
redirect_to [:admin, @api_user, @certificate]
end
def download_csr
send_data @certificate.csr, filename: "#{@api_user.username}.csr.pem"
end
def download_crt
send_data @certificate.crt, filename: "#{@api_user.username}.crt.pem"
end
private
def set_certificate
@certificate = Certificate.find(params[:id])
end
def set_api_user
@api_user = ApiUser.find(params[:api_user_id])
end
def certificate_params
params.require(:certificate).permit(:csr)
end
end

View file

@ -1,4 +1,3 @@
class AdminController < ApplicationController class AdminController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
check_authorization
end end

View file

@ -1,4 +1,6 @@
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
check_authorization unless: :devise_controller?
# 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
@ -9,8 +11,14 @@ class ApplicationController < ActionController::Base
params[resource] &&= send(method) if respond_to?(method, true) params[resource] &&= send(method) if respond_to?(method, true)
end end
rescue_from CanCan::AccessDenied do |exception|
redirect_to admin_dashboard_path, alert: exception.message
end
def after_sign_in_path_for(_resource) def after_sign_in_path_for(_resource)
return session[:user_return_to].to_s if session[:user_return_to] && session[:user_return_to] != login_path if session[:user_return_to] && session[:user_return_to] != login_path
return session[:user_return_to].to_s
end
admin_dashboard_path admin_dashboard_path
end end
@ -34,9 +42,3 @@ class ApplicationController < ActionController::Base
end end
end end
end end
class ApplicationController < ActionController::Base
rescue_from CanCan::AccessDenied do |exception|
redirect_to admin_dashboard_path, alert: exception.message
end
end

View file

@ -1,188 +1,125 @@
class Epp::ContactsController < EppController class Epp::ContactsController < EppController
helper WhodunnitHelper ## Refactor this? before_action :find_contact, only: [:info, :update, :delete]
before_action :find_password, only: [:info, :update, :delete]
def create
@contact = Contact.new(contact_and_address_attributes)
@contact.registrar = current_user.registrar
render_epp_response '/epp/contacts/create' and return if @contact.save
handle_errors(@contact)
end
def update
# FIXME: Update returns 2303 update multiple times
code = params_hash['epp']['command']['update']['update'][:id]
@contact = Contact.where(code: code).first
# if update_rights? && @contact.update_attributes(contact_and_address_attributes(:update))
if owner? && @contact.update_attributes(contact_and_address_attributes(:update))
render_epp_response 'epp/contacts/update'
else
contact_exists?(code)
handle_errors(@contact) and return
end
end
# rubocop:disable Metrics/CyclomaticComplexity
def delete
@contact = find_contact
handle_errors(@contact) and return unless rights? # owner?
handle_errors(@contact) and return unless @contact
handle_errors(@contact) and return unless @contact.destroy_and_clean
render_epp_response '/epp/contacts/delete'
end
# rubocop:enable Metrics/CyclomaticComplexity
def check
ph = params_hash['epp']['command']['check']['check']
@contacts = Contact.check_availability(ph[:id])
render_epp_response '/epp/contacts/check'
end
def info def info
handle_errors(@contact) and return unless @contact && rights? authorize! :info, @contact, @password
# handle_errors(@contact) and return unless rights?
@disclosure = ContactDisclosure.default_values.merge(@contact.disclosure.try(:as_hash) || {})
@disclosure_policy = @contact.disclosure.try(:attributes_with_flag)
@owner = owner?(false)
# need to reload contact eagerly
@contact = find_contact if @owner # for clarity, could just be true
render_epp_response 'epp/contacts/info' render_epp_response 'epp/contacts/info'
end end
def check
authorize! :check, Epp::Contact
ids = params[:parsed_frame].css('id').map(&:text)
@results = Contact.check_availability(ids)
render_epp_response '/epp/contacts/check'
end
def create
authorize! :create, Epp::Contact
@contact = Epp::Contact.new(params[:parsed_frame], current_user.registrar)
if @contact.save
render_epp_response '/epp/contacts/create'
else
handle_errors(@contact)
end
end
def update
authorize! :update, @contact, @password
if @contact.update_attributes(params[:parsed_frame])
render_epp_response 'epp/contacts/update'
else
handle_errors(@contact)
end
end
def delete
authorize! :delete, @contact, @password
if @contact.destroy_and_clean
render_epp_response '/epp/contacts/delete'
else
handle_errors(@contact)
end
end
def renew def renew
authorize! :renew, Epp::Contact
epp_errors << { code: '2101', msg: t(:'errors.messages.unimplemented_command') } epp_errors << { code: '2101', msg: t(:'errors.messages.unimplemented_command') }
handle_errors handle_errors
end end
## HELPER METHODS
private private
## CREATE def find_password
def validate_create @password = params[:parsed_frame].css('authInfo pw').text
@ph = params_hash['epp']['command']['create']['create']
return false unless validate_params
xml_attrs_present?(@ph, [%w(postalInfo name), %w(postalInfo addr city), %w(postalInfo addr cc),
%w(ident), %w(voice), %w(email)])
epp_errors.empty?
end end
## UPDATE
def validate_updatezz
@ph = params_hash['epp']['command']['update']['update']
update_attrs_present?
# xml_attrs_present?(@ph, [['id'], %w(authInfo pw)])
xml_attrs_present?(@ph, [['id']])
end
def contact_exists?(code)
return true if @contact.is_a?(Contact)
epp_errors << { code: '2303', msg: t('errors.messages.epp_obj_does_not_exist'),
value: { obj: 'id', val: code } }
end
def update_attrs_present?
return true if params[:parsed_frame].css('add').present?
return true if params[:parsed_frame].css('rem').present?
return true if params[:parsed_frame].css('chg').present?
epp_errors << { code: '2003', msg: I18n.t('errors.messages.required_parameter_missing', key: 'add, rem or chg') }
end
## DELETE
def validate_delete
@ph = params_hash['epp']['command']['delete']['delete']
xml_attrs_present?(@ph, [['id']])
end
## check
def validate_check
@ph = params_hash['epp']['command']['check']['check']
xml_attrs_present?(@ph, [['id']])
end
## info
def validate_info # and process
@ph = params_hash['epp']['command']['info']['info']
return false unless xml_attrs_present?(@ph, [['id']])
@contact = find_contact
return false unless @contact
return true if current_user.registrar == @contact.registrar || xml_attrs_present?(@ph, [%w(authInfo pw)])
false
end
## SHARED
def find_contact def find_contact
contact = Contact.find_by(code: @ph[:id]) code = params[:parsed_frame].css('id').text.strip.downcase
unless contact @contact = Epp::Contact.find_by(code: code)
epp_errors << { code: '2303',
if @contact.blank?
epp_errors << {
code: '2303',
msg: t('errors.messages.epp_obj_does_not_exist'), msg: t('errors.messages.epp_obj_does_not_exist'),
value: { obj: 'id', val: @ph[:id] } } value: { obj: 'id', val: code }
}
fail CanCan::AccessDenied
end end
contact @contact
end end
def owner?(with_errors = true) #
return false unless find_contact # Validations
return true if @contact.registrar == current_user.registrar #
return false unless with_errors def validate_info
epp_errors << { code: '2201', msg: t('errors.messages.epp_authorization_error') } @prefix = 'info > info >'
false requires 'id'
end end
def rights? def validate_check
pw = @ph.try(:[], :authInfo).try(:[], :pw) @prefix = 'check > check >'
requires 'id'
return true if current_user.try(:registrar) == @contact.try(:registrar)
return true if pw && @contact.auth_info_matches(pw) # @contact.try(:auth_info_matches, pw)
epp_errors << { code: '2200', msg: t('errors.messages.epp_authentication_error') }
false
end end
def update_rights? def validate_create
pw = @ph.try(:[], :authInfo).try(:[], :pw) @prefix = 'create > create >'
return true if pw && @contact.auth_info_matches(pw) requires(
epp_errors << { code: '2200', msg: t('errors.messages.epp_authentication_error') } 'postalInfo > name', 'postalInfo > addr > city',
false 'postalInfo > addr > cc', 'ident', 'voice', 'email'
end
def contact_and_address_attributes(type = :create)
case type
when :update
# TODO: support for rem/add
contact_hash = merge_attribute_hash(@ph[:chg], type).delete_if { |_k, v| v.empty? }
else
contact_hash = merge_attribute_hash(@ph, type)
end
contact_hash[:ident_type] = ident_type unless ident_type.nil?
contact_hash
end
def merge_attribute_hash(prms, type)
contact_hash = Contact.extract_attributes(prms, type)
contact_hash = contact_hash.merge(
Address.extract_attributes((prms.try(:[], :postalInfo) || []))
) )
contact_hash[:disclosure_attributes] = ident = params[:parsed_frame].css('ident')
ContactDisclosure.extract_attributes(params[:parsed_frame]) if ident.present? && ident.text != 'birthday' && ident.attr('cc').blank?
epp_errors << {
contact_hash code: '2003',
msg: I18n.t('errors.messages.required_attribute_missing', key: 'ident country code missing')
}
end
@prefix = nil
requires 'extension > extdata > legalDocument'
end end
def ident_type def validate_update
result = params[:parsed_frame].css('ident').first.try(:attributes).try(:[], 'type').try(:value) @prefix = 'update > update >'
return nil unless result if element_count('chg') == 0 && element_count('rem') == 0 && element_count('add') == 0
epp_errors << {
Contact::IDENT_TYPES.any? { |type| return type if result.include?(type) } code: '2003',
nil msg: I18n.t('errors.messages.required_parameter_missing', key: 'add, rem or chg')
}
end
requires 'id', 'authInfo > pw'
@prefix = nil
requires 'extension > extdata > legalDocument'
end end
def validate_params def validate_delete
return true if @ph @prefix = 'delete > delete >'
epp_errors << { code: '2001', msg: t(:'errors.messages.epp_command_syntax_error') } requires 'id', 'authInfo > pw'
false @prefix = nil
requires 'extension > extdata > legalDocument'
end end
end end

View file

@ -1,4 +1,6 @@
class Epp::DomainsController < EppController class Epp::DomainsController < EppController
skip_authorization_check # TODO: remove it
def create def create
@domain = Epp::EppDomain.new(domain_create_params) @domain = Epp::EppDomain.new(domain_create_params)
# @domain.parse_and_attach_domain_dependencies(params[:parsed_frame]) # @domain.parse_and_attach_domain_dependencies(params[:parsed_frame])
@ -334,7 +336,7 @@ class Epp::DomainsController < EppController
return domain if domain.auth_info == params[:parsed_frame].css('authInfo pw').text return domain if domain.auth_info == params[:parsed_frame].css('authInfo pw').text
if (domain.registrar != current_user.registrar && secure[:secure] == true) && if (domain.registrar != current_user.registrar) && secure[:secure] == true
epp_errors << { epp_errors << {
code: '2302', code: '2302',
msg: I18n.t('errors.messages.domain_exists_but_belongs_to_other_registrar'), msg: I18n.t('errors.messages.domain_exists_but_belongs_to_other_registrar'),

View file

@ -1,4 +1,6 @@
class Epp::ErrorsController < EppController class Epp::ErrorsController < EppController
skip_authorization_check # TODO: remove it
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'

View file

@ -1,4 +1,6 @@
class Epp::KeyrelaysController < EppController class Epp::KeyrelaysController < EppController
skip_authorization_check # TODO: remove it
# rubocop: disable Metrics/PerceivedComplexity # rubocop: disable Metrics/PerceivedComplexity
# rubocop: disable Metrics/CyclomaticComplexity # rubocop: disable Metrics/CyclomaticComplexity
def keyrelay def keyrelay

View file

@ -1,4 +1,6 @@
class Epp::PollsController < EppController class Epp::PollsController < EppController
skip_authorization_check # TODO: remove it
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'
@ -38,6 +40,6 @@ class Epp::PollsController < EppController
private private
def validate_poll def validate_poll
requires_attribute 'poll', 'op', values: %(ack req) requires_attribute 'poll', 'op', values: %(ack req), allow_blank: true
end end
end end

View file

@ -1,12 +1,24 @@
class Epp::SessionsController < EppController class Epp::SessionsController < EppController
skip_authorization_check only: [:hello, :login, :logout]
def hello def hello
render_epp_response('greeting') render_epp_response('greeting')
end end
# rubocop: disable Metrics/PerceivedComplexity
# rubocop: disable Metrics/CyclomaticComplexity
def login def login
cert_valid = true
if request.ip == ENV['webclient_ip']
@api_user = ApiUser.find_by(login_params) @api_user = ApiUser.find_by(login_params)
else
if request.env['HTTP_SSL_CLIENT_S_DN_CN'] != login_params[:username]
cert_valid = false
end
@api_user = ApiUser.find_by(login_params)
end
if @api_user.try(:active) if @api_user.try(:active) && cert_valid
epp_session[:api_user_id] = @api_user.id epp_session[:api_user_id] = @api_user.id
render_epp_response('login_success') render_epp_response('login_success')
else else
@ -14,6 +26,8 @@ class Epp::SessionsController < EppController
render_epp_response('login_fail') render_epp_response('login_fail')
end end
end end
# rubocop: enable Metrics/PerceivedComplexity
# rubocop: enable Metrics/CyclomaticComplexity
def logout def logout
@api_user = current_user # cache current_user for logging @api_user = current_user # cache current_user for logging

View file

@ -1,10 +1,23 @@
class EppController < ApplicationController class EppController < ApplicationController
layout false
protect_from_forgery with: :null_session protect_from_forgery with: :null_session
skip_before_action :verify_authenticity_token
before_action :generate_svtrid before_action :generate_svtrid
before_action :validate_request before_action :validate_request
layout false
helper_method :current_user helper_method :current_user
rescue_from CanCan::AccessDenied do |_exception|
@errors ||= []
if @errors.blank?
@errors = [{
msg: t('errors.messages.epp_authorization_error'),
code: '2201'
}]
end
render_epp_response '/epp/error'
end
def generate_svtrid def generate_svtrid
# rubocop: disable Style/VariableName # rubocop: disable Style/VariableName
@svTRID = "ccReg-#{format('%010d', rand(10**10))}" @svTRID = "ccReg-#{format('%010d', rand(10**10))}"
@ -84,15 +97,23 @@ class EppController < ApplicationController
# TODO: Add possibility to pass validations / options in the method # TODO: Add possibility to pass validations / options in the method
def requires(*selectors) def requires(*selectors)
options = selectors.extract_options!
allow_blank = options[:allow_blank] ||= false # allow_blank is false by default
el, missing = nil, nil el, missing = nil, nil
selectors.each do |selector| selectors.each do |selector|
full_selector = [@prefix, selector].compact.join(' ') full_selector = [@prefix, selector].compact.join(' ')
attr = selector.split('>').last.strip.underscore
el = params[:parsed_frame].css(full_selector).first el = params[:parsed_frame].css(full_selector).first
if allow_blank
missing = el.nil? missing = el.nil?
else
missing = el.present? ? el.text.blank? : true
end
epp_errors << { epp_errors << {
code: '2003', 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 } if missing
end end
@ -105,7 +126,7 @@ class EppController < ApplicationController
# requires_attribute 'transfer', 'op', values: %(approve, query, reject) # requires_attribute 'transfer', 'op', values: %(approve, query, reject)
def requires_attribute(element_selector, attribute_selector, options) def requires_attribute(element_selector, attribute_selector, options)
element = requires(element_selector) element = requires(element_selector, allow_blank: options[:allow_blank])
return unless element return unless element
attribute = element[attribute_selector] attribute = element[attribute_selector]

View file

@ -1,4 +1,6 @@
class SessionsController < Devise::SessionsController class SessionsController < Devise::SessionsController
skip_authorization_check
def create def create
# TODO: Create ID Card login here: # TODO: Create ID Card login here:
# this is just testing config # this is just testing config

View file

@ -8,4 +8,13 @@ module ApplicationHelper
return '' if unstable_env.nil? return '' if unstable_env.nil?
"background-image: url(#{image_path(unstable_env.to_s + '.png')});" "background-image: url(#{image_path(unstable_env.to_s + '.png')});"
end end
def ident_indicator(contact)
case contact.ident_type
when 'birthday'
"[#{contact.ident_type}]"
else
"[#{contact.ident_country_code} #{contact.ident_type}]"
end
end
end end

View file

@ -1,25 +0,0 @@
module WhodunnitHelper
def link_to_whodunnit(whodunnit)
return nil unless whodunnit
if whodunnit.include?('-ApiUser')
user = ApiUser.find(whodunnit)
return link_to(user.username, admin_epp_user_path(user))
end
user = AdminUser.find(whodunnit)
return link_to(user.username, admin_user_path(user))
rescue ActiveRecord::RecordNotFound
return nil
end
def whodunnit_with_protocol(whodunnit)
return nil unless whodunnit
if whodunnit.include?('-ApiUser')
user = ApiUser.find(whodunnit)
return "#{user.username} (EPP)"
end
user = AdminUser.find(whodunnit)
return user.username
rescue ActiveRecord::RecordNotFound
return nil
end
end

View file

@ -2,16 +2,31 @@ class Ability
include CanCan::Ability include CanCan::Ability
def initialize(user) def initialize(user)
alias_action :create, :read, :update, :destroy, to: :crud alias_action :show, :create, :update, :destroy, to: :crud
@user = user || AdminUser.new @user = user || AdminUser.new
@user.roles.each { |role| send(role) } if @user.roles
return if @user.roles || @user.roles.any? case @user.class.to_s
when 'AdminUser'
@user.roles.each { |role| send(role) } if @user.roles
when 'ApiUser'
epp
end
can :show, :dashboard can :show, :dashboard
end end
def epp
# Epp::Contact
can(:info, Epp::Contact) { |c, pw| c.registrar_id == @user.registrar_id || c.auth_info == pw }
can(:check, Epp::Contact)
can(:create, Epp::Contact)
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(:renew, Epp::Contact)
can(:view_password, Epp::Contact) { |c| c.registrar_id == @user.registrar_id }
end
def user def user
can :show, :dashboard can :show, :dashboard
end end
@ -30,6 +45,7 @@ class Ability
can :manage, DomainVersion can :manage, DomainVersion
can :manage, User can :manage, User
can :manage, ApiUser can :manage, ApiUser
can :manage, Certificate
can :manage, Keyrelay can :manage, Keyrelay
can :manage, LegalDocument can :manage, LegalDocument
can :read, ApiLog::EppLog can :read, ApiLog::EppLog

View file

@ -5,14 +5,24 @@ class ApiUser < User
# TODO: should have max request limit per day # TODO: should have max request limit per day
belongs_to :registrar belongs_to :registrar
has_many :contacts has_many :contacts
has_many :certificates
validates :username, :password, :registrar, presence: true validates :username, :password, :registrar, presence: true
validates :username, uniqueness: true validates :username, uniqueness: true
before_save :create_crt, if: -> (au) { au.csr_changed? }
attr_accessor :registrar_typeahead attr_accessor :registrar_typeahead
def ability
@ability ||= Ability.new(self)
end
delegate :can?, :cannot?, to: :ability
after_initialize :set_defaults
def set_defaults
return unless new_record?
self.active = true unless active_changed?
end
def registrar_typeahead def registrar_typeahead
@registrar_typeahead || registrar || nil @registrar_typeahead || registrar || nil
end end
@ -24,28 +34,5 @@ class ApiUser < User
def queued_messages def queued_messages
registrar.messages.queued registrar.messages.queued
end end
def create_crt
csr_file = Tempfile.new('client_csr')
csr_file.write(csr)
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']} \
-extensions usr_cert -notext -md sha256 \
-in #{csr_file.path} -out #{crt_file.path} -key '#{APP_CONFIG['ca_key_password']}' -batch")
if err.match(/Data Base Updated/)
crt_file.rewind
self.crt = crt_file.read
return true
else
errors.add(:base, I18n.t('failed_to_create_certificate'))
logger.error('FAILED TO CREATE CLIENT CERTIFICATE')
logger.error(err)
return false
end
end
end end
# rubocop: enable Metrics/ClassLength # rubocop: enable Metrics/ClassLength

View file

@ -32,10 +32,10 @@ class ApiUserDeprecated < ActiveRecord::Base
csr_file.rewind csr_file.rewind
crt_file = Tempfile.new('client_crt') crt_file = Tempfile.new('client_crt')
_out, err, _st = Open3.capture3("openssl ca -keyfile #{APP_CONFIG['ca_key_path']} \ _out, err, _st = Open3.capture3("openssl ca -keyfile #{ENV['ca_key_path']} \
-cert #{APP_CONFIG['ca_cert_path']} \ -cert #{ENV['ca_cert_path']} \
-extensions usr_cert -notext -md sha256 \ -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/) if err.match(/Data Base Updated/)
crt_file.rewind crt_file.rewind

88
app/models/certificate.rb Normal file
View file

@ -0,0 +1,88 @@
class Certificate < ActiveRecord::Base
include Versions
belongs_to :api_user
SIGNED = 'signed'
UNSIGNED = 'unsigned'
EXPIRED = 'expired'
REVOKED = 'revoked'
VALID = 'valid'
validates :csr, presence: true
def parsed_crt
@p_crt ||= OpenSSL::X509::Certificate.new(crt) if crt
end
def parsed_csr
@p_csr ||= OpenSSL::X509::Request.new(csr) if csr
end
def revoked?
status == REVOKED
end
def status
return UNSIGNED if crt.blank?
return @cached_status if @cached_status
@cached_status = SIGNED
if parsed_crt.not_before > Time.now.utc && parsed_crt.not_after < Time.now.utc
@cached_status = EXPIRED
end
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
end
def sign!
csr_file = Tempfile.new('client_csr')
csr_file.write(csr)
csr_file.rewind
crt_file = Tempfile.new('client_crt')
_out, err, _st = Open3.capture3("openssl ca -config #{ENV['openssl_config_path']} -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 '#{ENV['ca_key_password']}' -batch")
if err.match(/Data Base Updated/)
crt_file.rewind
self.crt = crt_file.read
save!
else
errors.add(:base, I18n.t('failed_to_create_certificate'))
logger.error('FAILED TO CREATE CLIENT CERTIFICATE')
logger.error(err)
return false
end
end
def revoke!
crt_file = Tempfile.new('client_crt')
crt_file.write(crt)
crt_file.rewind
_out, err, _st = Open3.capture3("openssl ca -config #{ENV['openssl_config_path']} -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!
@cached_status = REVOKED
else
errors.add(:base, I18n.t('failed_to_revoke_certificate'))
logger.error('FAILED TO REVOKE CLIENT CERTIFICATE')
logger.error(err)
return false
end
_out, _err, _st = Open3.capture3("openssl ca -config #{ENV['openssl_config_path']} -keyfile #{ENV['ca_key_path']} \
-cert #{ENV['ca_cert_path']} \
-gencrl -out #{ENV['crl_path']} -key '#{ENV['ca_key_password']}' -batch")
end
end

View file

@ -3,42 +3,43 @@ module EppErrors
def construct_epp_errors def construct_epp_errors
epp_errors = [] epp_errors = []
errors.messages.each do |key, values| errors.messages.each do |attr, errors|
key = key.to_s.split('.')[0].to_sym attr = attr.to_s.split('.')[0].to_sym
next if key == :epp_errors next if attr == :epp_errors
if self.class.reflect_on_association(key) if self.class.reflect_on_association(attr)
epp_errors << collect_child_errors(key) epp_errors << collect_child_errors(attr)
end end
epp_errors << collect_parent_errors(values) epp_errors << collect_parent_errors(attr, errors)
end end
errors[:epp_errors] = epp_errors errors[:epp_errors] = epp_errors
errors[:epp_errors].flatten! errors[:epp_errors].flatten!
end end
def collect_parent_errors(values) def collect_parent_errors(attr, errors)
epp_errors = [] errors = [errors] if errors.is_a?(String)
values = [values] if values.is_a?(String)
values.each do |err| epp_errors = []
errors.each do |err|
code, value = find_epp_code_and_value(err) code, value = find_epp_code_and_value(err)
next unless code 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 end
epp_errors epp_errors
end end
def collect_child_errors(key) def collect_child_errors(attr)
macro = self.class.reflect_on_association(key).macro macro = self.class.reflect_on_association(attr).macro
multi = [:has_and_belongs_to_many, :has_many] multi = [:has_and_belongs_to_many, :has_many]
# single = [:belongs_to, :has_one] # single = [:belongs_to, :has_one]
epp_errors = [] epp_errors = []
send(key).each do |x| send(attr).each do |x|
x.errors.messages.each do |_key, values| x.errors.messages.each do |attribute, errors|
epp_errors << x.collect_parent_errors(values) epp_errors << x.collect_parent_errors(attribute, errors)
end end
end if multi.include?(macro) end if multi.include?(macro)

View file

@ -5,7 +5,7 @@ module VersionSession
before_save :add_session before_save :add_session
def add_session def add_session
self.session = PaperSession.session self.session = ::PaperSession.session
true true
end end
end end

View file

@ -28,9 +28,9 @@ module Versions
return nil if creator_str.blank? return nil if creator_str.blank?
if creator_str =~ /^\d-api-/ if creator_str =~ /^\d-api-/
ApiUser.find(creator_str) ApiUser.find_by(id: creator_str)
else else
AdminUser.find(creator_str) AdminUser.find_by(id: creator_str)
end end
end end
@ -38,9 +38,9 @@ module Versions
return nil if updator_str.blank? return nil if updator_str.blank?
if updator_str =~ /^\d-api-/ if updator_str =~ /^\d-api-/
ApiUser.find(updator_str) ApiUser.find_by(id: updator_str)
else else
AdminUser.find(updator_str) AdminUser.find_by(id: updator_str)
end end
end end

View file

@ -1,6 +1,5 @@
class Contact < ActiveRecord::Base class Contact < ActiveRecord::Base
include Versions # version/contact_version.rb include Versions # version/contact_version.rb
include EppErrors
has_one :address, dependent: :destroy has_one :address, dependent: :destroy
has_one :disclosure, class_name: 'ContactDisclosure', dependent: :destroy has_one :disclosure, class_name: 'ContactDisclosure', dependent: :destroy
@ -8,45 +7,46 @@ class Contact < ActiveRecord::Base
has_many :domain_contacts has_many :domain_contacts
has_many :domains, through: :domain_contacts has_many :domains, through: :domain_contacts
has_many :statuses, class_name: 'ContactStatus' has_many :statuses, class_name: 'ContactStatus'
has_many :legal_documents, as: :documentable
belongs_to :registrar belongs_to :registrar
accepts_nested_attributes_for :address, :disclosure accepts_nested_attributes_for :address, :disclosure, :legal_documents
validates :name, :phone, :email, :ident, :address, :registrar, :ident_type, presence: true validates :name, :phone, :email, :ident, :address, :registrar, :ident_type, presence: true
# Phone nr validation is very minimam in order to support legacy requirements # Phone nr validation is very minimam in order to support legacy requirements
validates :phone, format: /\+[0-9]{1,3}\.[0-9]{1,14}?/ validates :phone, format: /\+[0-9]{1,3}\.[0-9]{1,14}?/
validates :email, format: /@/ validates :email, format: /@/
validates :ident, format: /\d{4}-\d{2}-\d{2}/, if: proc { |c| c.ident_type == 'birthday' } validates :ident,
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 },
format: { with: /\A[\w\-\:]*\Z/i },
length: { maximum: 100 }
validate :ident_must_be_valid validate :ident_valid_format?
validates :code, uniqueness: { message: :epp_id_taken } delegate :street, to: :address
delegate :city, to: :address
delegate :zip, to: :address
delegate :state, to: :address
delegate :country_code, to: :address
delegate :country, to: :address
delegate :city, to: :address # , prefix: true before_validation :set_ident_country_code
delegate :street, to: :address # , prefix: true
delegate :zip, to: :address # , prefix: true
# callbacks
# TODO: remove old
# after_commit :domains_snapshot
# after_update :domains_snapshot
# after_destroy :domains_snapshot
before_create :generate_code before_create :generate_code
before_create :generate_auth_info before_create :generate_auth_info
after_create :ensure_disclosure after_create :ensure_disclosure
# scopes
scope :current_registrars, ->(id) { where(registrar_id: id) } scope :current_registrars, ->(id) { where(registrar_id: id) }
IDENT_TYPE_ICO = 'ico' IDENT_TYPE_BIC = 'bic'
IDENT_TYPES = [ IDENT_TYPES = [
IDENT_TYPE_ICO, # Company registry code (or similar) IDENT_TYPE_BIC, # Company registry code (or similar)
'bic', # Business registry code
'priv', # National idendtification number 'priv', # National idendtification number
'op', # Estonian ID, depricated
'passport', # Passport number, depricated
'birthday' # Birthday date 'birthday' # Birthday date
] ]
@ -54,124 +54,10 @@ class Contact < ActiveRecord::Base
CONTACT_TYPE_ADMIN = 'admin' CONTACT_TYPE_ADMIN = 'admin'
CONTACT_TYPES = [CONTACT_TYPE_TECH, CONTACT_TYPE_ADMIN] CONTACT_TYPES = [CONTACT_TYPE_TECH, CONTACT_TYPE_ADMIN]
def ident_must_be_valid
# TODO: Ident can also be passport number or company registry code.
# so have to make changes to validations (and doc/schema) accordingly
return true unless ident.present? && ident_type.present? && ident_type == 'op'
code = Isikukood.new(ident)
errors.add(:ident, 'bad format') unless code.valid?
end
def ensure_disclosure
create_disclosure! unless disclosure
end
# TODO: remove old
# def domains_snapshot
# (domains + domains_owned).uniq.each do |domain|
# next unless domain.is_a?(Domain)
# # next if domain.versions.last == domain.create_snapshot
# domain.create_version # Method from paper_trail
# end
# end
def juridical?
ident_type == IDENT_TYPE_ICO
end
def citizen?
ident_type != IDENT_TYPE_ICO
end
def cr_id
# created_by ? created_by.username : nil
end
def up_id
# updated_by ? updated_by.username : nil
end
def auth_info_matches(pw)
auth_info == pw
end
# generate random id for contact
def generate_code
self.code = SecureRandom.hex(4)
end
def generate_auth_info
self.auth_info = SecureRandom.hex(16)
end
# Find a way to use self.domains with contact
def domains_owned
Domain.where(owner_contact_id: id)
end
def relations_with_domain?
return true if domain_contacts.present? || domains_owned.present?
false
end
# should use only in transaction
def destroy_and_clean
if relations_with_domain?
errors.add(:domains, :exist)
return false
end
destroy
end
def epp_code_map # rubocop:disable Metrics/MethodLength
{
'2302' => [ # Object exists
[:code, :epp_id_taken]
],
'2305' => [ # Association exists
[:domains, :exist]
],
'2005' => [ # Value syntax error
[:phone, :invalid],
[:email, :invalid],
[:ident, :invalid]
]
}
end
def to_s
name
end
# TODO: remove old
# for archiving
# def snapshot
# {
# name: name,
# phone: phone,
# code: code,
# ident: ident,
# email: email
# }
# end
class << self class << self
# non-EPP def search_by_query(query)
res = search(code_cont: query).result
# EPP res.reduce([]) { |o, v| o << { id: v[:id], display_key: "#{v.name} (#{v.code})" } }
def extract_attributes(ph, _type = :create)
ph[:postalInfo] = ph[:postalInfo].first if ph[:postalInfo].is_a?(Array)
contact_hash = {
phone: ph[:voice],
ident: ph[:ident],
ident_type: ph[:ident_type],
email: ph[:email],
fax: ph[:fax],
name: ph[:postalInfo].try(:[], :name),
org_name: ph[:postalInfo].try(:[], :org)
}
# contact_hash[:auth_info] = ph[:authInfo][:pw] if type == :create
contact_hash.delete_if { |_k, v| v.nil? }
end end
def check_availability(codes) def check_availability(codes)
@ -188,10 +74,84 @@ class Contact < ActiveRecord::Base
res res
end end
end
def search_by_query(query) def to_s
res = search(code_cont: query).result name
res.reduce([]) { |o, v| o << { id: v[:id], display_key: "#{v.name} (#{v.code})" } } end
def ident_valid_format?
case ident_type
when 'priv'
case ident_country_code
when 'EE'
code = Isikukood.new(ident)
errors.add(:ident, :invalid_EE_identity_format) unless code.valid?
end
end
end
def ensure_disclosure
create_disclosure! unless disclosure
end
def bic?
ident_type == IDENT_TYPE_BIC
end
def priv?
ident_type != IDENT_TYPE_BIC
end
def generate_code
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)
end
def relations_with_domain?
return true if domain_contacts.present? || domains_owned.present?
false
end
# TODO: refactor, it should not allow to destroy with normal destroy,
# no need separate method
# should use only in transaction
def destroy_and_clean
if relations_with_domain?
errors.add(:domains, :exist)
return false
end
destroy
end
def set_ident_country_code
return true unless ident_country_code_changed? && ident_country_code.present?
code = Country.new(ident_country_code)
if code
self.ident_country_code = code.alpha2
else
errors.add(:ident_country_code, 'is not following ISO_3166-1 alpha 2 format')
end end
end end
end end

View file

@ -85,9 +85,9 @@ class Dnskey < ActiveRecord::Base
end end
def generate_ds_key_tag def generate_ds_key_tag
public_key.gsub!(' ', '') pk = public_key.gsub(' ', '')
wire_format = [flags, protocol, alg].pack('S!>CC') wire_format = [flags, protocol, alg].pack('S!>CC')
wire_format += Base64.decode64(public_key) wire_format += Base64.decode64(pk)
c = 0 c = 0
wire_format.each_byte.with_index do |b, i| wire_format.each_byte.with_index do |b, i|

View file

@ -20,8 +20,6 @@ class Domain < ActiveRecord::Base
-> { where(domain_contacts: { contact_type: DomainContact::ADMIN }) }, -> { where(domain_contacts: { contact_type: DomainContact::ADMIN }) },
through: :domain_contacts, source: :contact through: :domain_contacts, source: :contact
# TODO: remove old
# has_many :nameservers, dependent: :delete_all, after_add: :track_nameserver_add
has_many :nameservers, dependent: :delete_all has_many :nameservers, dependent: :delete_all
accepts_nested_attributes_for :nameservers, allow_destroy: true, accepts_nested_attributes_for :nameservers, allow_destroy: true,
@ -118,11 +116,6 @@ class Domain < ActiveRecord::Base
attr_accessor :owner_contact_typeahead, :update_me attr_accessor :owner_contact_typeahead, :update_me
# TODO: remove old
# archiving
# if proc works only on changes on domain sadly
# has_paper_trail class_name: 'DomainVersion', meta: { snapshot: :create_snapshot }, if: proc(&:new_version)
def tech_domain_contacts def tech_domain_contacts
domain_contacts.select { |x| x.contact_type == DomainContact::TECH } domain_contacts.select { |x| x.contact_type == DomainContact::TECH }
end end
@ -131,52 +124,6 @@ class Domain < ActiveRecord::Base
domain_contacts.select { |x| x.contact_type == DomainContact::ADMIN } domain_contacts.select { |x| x.contact_type == DomainContact::ADMIN }
end end
# TODO: remove old
# def new_version
# return false if versions.try(:last).try(:snapshot) == create_snapshot
# true
# end
# TODO: remove old
# def create_version
# return true unless PaperTrail.enabled?
# return true unless valid?
# touch_with_version if new_version
# end
# TODO: remove old
# def track_nameserver_add(_nameserver)
# return true if versions.count == 0
# return true unless valid? && new_version
# touch_with_version
# end
# TODO: remove old
# def create_snapshot
# oc = owner_contact.snapshot if owner_contact.is_a?(Contact)
# {
# owner_contact: oc,
# tech_contacts: tech_contacts.map(&:snapshot),
# admin_contacts: admin_contacts.map(&:snapshot),
# nameservers: nameservers.map(&:snapshot),
# domain: make_snapshot
# }.to_yaml
# end
# TODO: remove old
# def make_snapshot
# {
# name: name,
# status: status,
# period: period,
# period_unit: period_unit,
# registrar_id: registrar.try(:id),
# valid_to: valid_to,
# valid_from: valid_from
# }
# end
def name=(value) def name=(value)
value.strip! value.strip!
value.downcase! value.downcase!
@ -265,7 +212,7 @@ class Domain < ActiveRecord::Base
attach_contact(DomainContact::TECH, owner_contact) attach_contact(DomainContact::TECH, owner_contact)
end end
return unless admin_domain_contacts.count.zero? && owner_contact.citizen? return unless admin_domain_contacts.count.zero? && owner_contact.priv?
attach_contact(DomainContact::ADMIN, owner_contact) attach_contact(DomainContact::ADMIN, owner_contact)
end end

102
app/models/epp/contact.rb Normal file
View file

@ -0,0 +1,102 @@
# rubocop: disable Metrics/ClassLength
class Epp::Contact < Contact
include EppErrors
# disable STI, there is type column present
self.inheritance_column = :sti_disabled
class << self
# rubocop: disable Metrics/PerceivedComplexity
# rubocop: disable Metrics/CyclomaticComplexity
# rubocop: disable Metrics/MethodLength
def attrs_from(frame)
f = frame
at = {}.with_indifferent_access
at[:name] = f.css('postalInfo name').text if f.css('postalInfo name').present?
at[:org_name] = f.css('postalInfo org').text if f.css('postalInfo org').present?
at[:email] = f.css('email').text if f.css('email').present?
at[:fax] = f.css('fax').text if f.css('fax').present?
at[:phone] = f.css('voice').text if f.css('voice').present?
at[:auth_info] = f.css('authInfo pw').text if f.css('authInfo pw').present?
if f.css('ident').present? && f.css('ident').attr('type').present?
at[:ident] = f.css('ident').text
at[:ident_type] = f.css('ident').attr('type').try(:text)
at[:ident_country_code] = f.css('ident').attr('cc').try(:text)
end
at[:address_attributes] = {}.with_indifferent_access
sat = at[:address_attributes]
sat[:city] = f.css('postalInfo addr city').text if f.css('postalInfo addr city').present?
sat[:zip] = f.css('postalInfo addr pc').text if f.css('postalInfo addr pc').present?
sat[:street] = f.css('postalInfo addr street').text if f.css('postalInfo addr street').present?
sat[:state] = f.css('postalInfo addr sp').text if f.css('postalInfo addr sp').present?
sat[:country_code] = f.css('postalInfo addr cc').text if f.css('postalInfo addr cc').present?
at.delete(:address_attributes) if at[:address_attributes].blank?
legal_frame = f.css('legalDocument').first
if legal_frame.present?
at[:legal_documents_attributes] = legal_document_attrs(legal_frame)
end
at
end
# rubocop: enable Metrics/MethodLength
# rubocop: enable Metrics/PerceivedComplexity
# rubocop: enable Metrics/CyclomaticComplexity
def new(frame, registrar)
return super if frame.blank?
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)
[{
body: legal_frame.text,
document_type: legal_frame['type']
}]
end
end
def epp_code_map # rubocop:disable Metrics/MethodLength
{
'2302' => [ # Object exists
[:code, :epp_id_taken]
],
'2305' => [ # Association exists
[:domains, :exist]
],
'2005' => [ # Value syntax error
[:phone, :invalid],
[:email, :invalid],
[:ident, :invalid],
[:ident, :invalid_EE_identity_format],
[:ident, :invalid_birthday_format]
]
}
end
def update_attributes(frame)
return super if frame.blank?
at = {}.with_indifferent_access
at.deep_merge!(self.class.attrs_from(frame.css('chg')))
legal_frame = frame.css('legalDocument').first
at[:legal_documents_attributes] = self.class.legal_document_attrs(legal_frame)
super(at)
end
end
# rubocop: enable Metrics/ClassLength

View file

@ -146,7 +146,7 @@ class Epp::EppDomain < Domain
next next
end end
if k == :admin && contact.juridical? if k == :admin && contact.bic?
add_epp_error('2306', 'contact', x[:contact], [:domain_contacts, :admin_contact_can_be_only_citizen]) add_epp_error('2306', 'contact', x[:contact], [:domain_contacts, :admin_contact_can_be_only_citizen])
next next
end end

View file

@ -9,10 +9,18 @@ class Registrar < ActiveRecord::Base
validates :name, :reg_no, :country_code, :email, presence: true validates :name, :reg_no, :country_code, :email, presence: true
validates :name, :reg_no, uniqueness: true validates :name, :reg_no, uniqueness: true
validate :set_code, if: :new_record?
after_save :touch_domains_version after_save :touch_domains_version
validates :email, :billing_email, format: /@/, allow_blank: true 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 def domain_transfers
at = DomainTransfer.arel_table at = DomainTransfer.arel_table
DomainTransfer.where( DomainTransfer.where(
@ -23,7 +31,7 @@ class Registrar < ActiveRecord::Base
end end
def address def address
[street, city, state, zip].reject(&:empty?).compact.join(', ') [street, city, state, zip].reject(&:blank?).compact.join(', ')
end end
def to_s def to_s
@ -34,10 +42,23 @@ class Registrar < ActiveRecord::Base
Country.new(country_code) Country.new(country_code)
end end
class << self def code=(code)
def search_by_query(query) self[:code] = code if new_record?
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
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
end end

View file

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

View file

@ -18,7 +18,7 @@ class ZonefileSetting < ActiveRecord::Base
"select generate_zonefile('#{origin}')" "select generate_zonefile('#{origin}')"
)[0]['generate_zonefile'] )[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" STDOUT << "#{Time.now.utc} - Successfully generated zonefile #{filename}\n"
end end

View file

@ -7,7 +7,7 @@
%hr %hr
.row .row
.col-md-6 .col-md-12
.form-group .form-group
= f.label :username = f.label :username
= f.text_field(:username, class: 'form-control') = f.text_field(:username, class: 'form-control')
@ -26,11 +26,6 @@
%label{for: 'api_user_active'} %label{for: 'api_user_active'}
= f.check_box(:active) = f.check_box(:active)
= t('active') = t('active')
.col-md-6.text-left
.form-group
= f.label :csr, t('certificate_signing_req')
= f.file_field :csr
%hr %hr
.row .row
.col-md-12.text-right .col-md-12.text-right

View file

@ -15,7 +15,7 @@
- if @api_user.errors.any? - if @api_user.errors.any?
%hr %hr
.row .row
.col-md-6 .col-md-12
.panel.panel-default .panel.panel-default
.panel-heading .panel-heading
%h3.panel-title= t('general') %h3.panel-title= t('general')
@ -29,21 +29,24 @@
%dt= t('active') %dt= t('active')
%dd= @api_user.active %dd= @api_user.active
.row
.col-md-6 .col-md-12
.panel.panel-default .panel.panel-default
.panel-heading .panel-heading.clearfix
%h3.panel-title= t('certificates') .pull-left
.panel-body = t('certificates')
%dl.dl-horizontal .pull-right
%dt= t('csr') = link_to(t('upload_csr'), new_admin_api_user_certificate_path(@api_user), class: 'btn btn-primary btn-xs')
- if @api_user.csr
%dd= link_to(t('download'), download_csr_admin_api_user_path)
- else
%dd -
%dt= t('crt') .table-responsive
- if @api_user.csr %table.table.table-hover.table-bordered.table-condensed
%dd= link_to(t('download'), download_crt_admin_api_user_path) %thead
- else %tr
%dd - %th{class: 'col-xs-10'}= t('subject')
%th{class: 'col-xs-2'}= t('status')
%tbody
- @api_user.certificates.each do |x|
- if x.csr
%tr
%td= link_to(x.parsed_csr.try(:subject), admin_api_user_certificate_path(@api_user, x))
%td= x.status

View file

@ -0,0 +1,20 @@
%h2= t('upload_csr')
%hr
= form_for([:admin, @api_user, @certificate], multipart: true) do |f|
- if @certificate.errors.any?
- @certificate.errors.each do |attr, err|
= err
%br
- if @certificate.errors.any?
%hr
.row
.col-md-12.text-left
.form-group
= f.label :csr, t('certificate_signing_req')
= f.file_field :csr
%hr
.row
.col-md-12.text-right
= button_tag(t('save'), class: 'btn btn-primary')

View file

@ -0,0 +1,75 @@
.row
.col-sm-6
%h2.text-center-xs
= t('certificates')
.col-sm-6
%h2.text-right.text-center-xs
= link_to(t('back_to_api_user'), [:admin, @api_user], class: 'btn btn-default')
%hr
- if @certificate.errors.any?
- @certificate.errors.each do |attr, err|
= err
%br
- if @certificate.errors.any?
%hr
.row
.col-md-12
.panel.panel-default
.panel-heading.clearfix
.pull-left
= t('csr')
.pull-right
= link_to(t('download'), download_csr_admin_api_user_certificate_path(@api_user, @certificate), class: 'btn btn-default btn-xs')
- unless @crt
= link_to(t('sign_this_request'), sign_admin_api_user_certificate_path(@api_user, @certificate), method: :post, class: 'btn btn-primary btn-xs')
.panel-body
%dl.dl-horizontal
%dt= t('version')
%dd= @csr.version
%dt= t('subject')
%dd= @csr.subject
%dt= t('signature_algorithm')
%dd= @csr.signature_algorithm
- if @crt
.row
.col-md-12
.panel.panel-default
.panel-heading.clearfix
.pull-left
= t('crt') unless @certificate.revoked?
= t('crt_revoked') if @certificate.revoked?
.pull-right
= link_to(t('download'), download_crt_admin_api_user_certificate_path(@api_user, @certificate), class: 'btn btn-default btn-xs')
- unless @certificate.revoked?
= link_to(t('revoke_this_certificate'), revoke_admin_api_user_certificate_path(@api_user, @certificate), method: :post, class: 'btn btn-primary btn-xs')
- if @crt
.panel-body
%dl.dl-horizontal
%dt= t('version')
%dd= @crt.version
%dt= t('serial_number')
%dd= @crt.serial
%dt= t('signature_algorithm')
%dd= @crt.signature_algorithm
%dt= t('issuer')
%dd= @crt.issuer
%dt= t('valid_from')
%dd= @crt.not_before
%dt= t('valid_to')
%dd= @crt.not_after
%dt= t('subject')
%dd= @crt.subject
%dt= t('extensions')
%dd= @crt.extensions.map(&:to_s).join('<br>').html_safe

View file

@ -22,20 +22,20 @@
%thead %thead
%tr %tr
%th{class: 'col-xs-2'} %th{class: 'col-xs-2'}
= sort_link(@q, 'name', t('name')) = sort_link(@q, 'name', t(:name))
%th{class: 'col-xs-2'} %th{class: 'col-xs-2'}
= sort_link(@q, 'code', t('code')) = sort_link(@q, 'ident', t(:identity))
%th{class: 'col-xs-2'} %th{class: 'col-xs-2'}
= sort_link(@q, 'ident', t('identity_code')) = sort_link(@q, 'email', t(:email))
%th{class: 'col-xs-2'} %th{class: 'col-xs-2'}
= sort_link(@q, 'email', t('email')) = sort_link(@q, 'code', t(:code))
%tbody %tbody
- @contacts.each do |x| - @contacts.each do |contact|
%tr %tr
%td= link_to(x, admin_contact_path(x)) %td= link_to(contact, admin_contact_path(contact))
%td= x.code %td= "#{contact.ident} #{ident_indicator(contact)}"
%td= x.ident %td= contact.email
%td= x.email %td= contact.code
.row .row
.col-md-12 .col-md-12
= paginate @contacts = paginate @contacts

View file

@ -1,28 +1,24 @@
.panel.panel-default .panel.panel-default
.panel-heading .panel-heading
%h3.panel-title= t('address') %h3.panel-title= t(:address)
.panel-body .panel-body
- unless @contact.address.nil? - unless @contact.address.nil?
%dl.dl-horizontal %dl.dl-horizontal
%dt= t('country') - if @contact.bic?
%dd= @contact.address.country %dt= t(:org_name)
%dd= @contact.org_name
%dt= t('city') %dt= t(:street)
%dd= @contact.address.city %dd= @contact.street
%dt= t('street') %dt= t(:city)
%dd= @contact.address.street %dd= @contact.city
- if @contact.address.street2 %dt= t(:zip)
%dt= t('street') %dd= @contact.zip
%dd= @contact.address.street2
- if @contact.address.street3 %dt= t(:state)
%dt= t('street') %dd= @contact.state
%dd= @contact.address.street3
%dt= t('zip')
%dd= @contact.address.zip
%dt= t(:country)
%dd= @contact.country

View file

@ -3,30 +3,25 @@
%h3.panel-title= t('general') %h3.panel-title= t('general')
.panel-body .panel-body
%dl.dl-horizontal %dl.dl-horizontal
%dt= t('name') %dt= t(:ident)
%dd= @contact.name %dd= "#{@contact.ident} #{ident_indicator(@contact)}"
%dt= t('org_name') %br
%dd= @contact.org_name
%dt= t('code') %dt= t(:email)
%dd= @contact.code
%dt= t('ident')
%dd= @contact.ident
%dt= t('ident_type')
%dd= @contact.ident_type
%dt= t('email')
%dd= @contact.email %dd= @contact.email
%dt= t('phone') %dt= t(:phone)
%dd= @contact.phone %dd= @contact.phone
- if @contact.fax - if @contact.fax
%dt= t('fax') %dt= t(:fax)
%dd= @contact.fax %dd= @contact.fax
%br
%dt= t(:code)
%dd= @contact.code
%dt= t('password') %dt= t('password')
%dd= @contact.auth_info %dd= @contact.auth_info

View file

@ -1,10 +1,13 @@
.row .row
.col-sm-12 .col-sm-12
%h2.text-center-xs %h2.text-center-xs
= "#{t('contact_details')}" = @contact.name
%hr %hr
.row .row
.col-md-6= render 'admin/contacts/partials/general' .col-md-6= render 'admin/contacts/partials/general'
.col-md-6= render 'admin/contacts/partials/address' .col-md-6= render 'admin/contacts/partials/address'
.row .row
.col-md-12= render 'admin/contacts/partials/domains' .col-md-12= render 'admin/contacts/partials/domains'
.row
.col-md-12
= render 'admin/domains/partials/legal_documents', legal_documents: @contact.legal_documents

View file

@ -8,7 +8,7 @@
%th{class: 'col-xs-8'}= t('created_at') %th{class: 'col-xs-8'}= t('created_at')
%th{class: 'col-xs-4'}= t('type') %th{class: 'col-xs-4'}= t('type')
%tbody %tbody
- @domain.legal_documents.each do |x| - legal_documents.each do |x|
%tr %tr
%td= link_to(x.created_at, [:admin, x]) %td= link_to(x.created_at, [:admin, x])
%td= x.document_type %td= x.document_type

View file

@ -24,4 +24,5 @@
.row .row
.col-md-12= render 'admin/domains/partials/keyrelays' .col-md-12= render 'admin/domains/partials/keyrelays'
.row .row
.col-md-12= render 'admin/domains/partials/legal_documents' .col-md-12
= render 'admin/domains/partials/legal_documents', legal_documents: @domain.legal_documents

View file

@ -1,13 +1,13 @@
address = @contact.address
xml.tag!('contact:postalInfo', type: 'int') do xml.tag!('contact:postalInfo', type: 'int') do
xml.tag!('contact:name', @contact.name) if @disclosure.try(:[], :name) || @owner xml.tag!('contact:name', @contact.name) #if @disclosure.try(:[], :name) || @owner
xml.tag!('contact:org', @contact.org_name) if @disclosure.try(:[], :org_name) || @owner xml.tag!('contact:org', @contact.org_name) #if @disclosure.try(:[], :org_name) || @owner
if @disclosure.try(:addr) || @owner # if @disclosure.try(:addr) || @owner
xml.tag!('contact:addr') do xml.tag!('contact:addr') do
xml.tag!('contact:street', address.street) if address xml.tag!('contact:street', @contact.street)
xml.tag!('contact:cc', address.country_code) unless address.country_code.nil? xml.tag!('contact:city', @contact.city)
xml.tag!('contact:city', address.city) if address xml.tag!('contact:pc', @contact.zip)
end xml.tag!('contact:sp', @contact.state)
xml.tag!('contact:cc', @contact.country_code)
end end
# end
end end

View file

@ -6,11 +6,10 @@ xml.epp_head do
xml.resData do xml.resData do
xml.tag!('contact:chkData', 'xmlns:contact' => 'urn:ietf:params:xml:ns:contact-1.0') do xml.tag!('contact:chkData', 'xmlns:contact' => 'urn:ietf:params:xml:ns:contact-1.0') do
#xml.tag!('contact:id', @contact.code) @results.each do |result|
@contacts.each do |contact|
xml.tag!('contact:cd') do xml.tag!('contact:cd') do
xml.tag! "contact:id", contact[:code], avail: contact[:avail] xml.tag! "contact:id", result[:code], avail: result[:avail]
xml.tag!('contact:reason', contact[:reason]) unless contact[:avail] == 1 xml.tag!('contact:reason', result[:reason]) unless result[:avail] == 1
end end
end end
end end

View file

@ -8,9 +8,9 @@ xml.epp_head do
xml.tag!('contact:chkData', 'xmlns:contact' => 'urn:ietf:params:xml:ns:contact-1.0') do xml.tag!('contact:chkData', 'xmlns:contact' => 'urn:ietf:params:xml:ns:contact-1.0') do
xml.tag!('contact:id', @contact.code) xml.tag!('contact:id', @contact.code)
xml << render('/epp/contacts/postal_info') xml << render('/epp/contacts/postal_info')
xml.tag!('contact:voice', @contact.phone) if @disclosure.try(:phone) || @owner xml.tag!('contact:voice', @contact.phone) #if @disclosure.try(:phone) || @owner
xml.tag!('contact:fax', @contact.fax) if @disclosure.try(:fax) || @owner xml.tag!('contact:fax', @contact.fax) #if @disclosure.try(:fax) || @owner
xml.tag!('contact:email', @contact.email) if @disclosure.try(:email) || @owner xml.tag!('contact:email', @contact.email) #if @disclosure.try(:email) || @owner
xml.tag!('contact:clID', @contact.registrar.try(:name)) xml.tag!('contact:clID', @contact.registrar.try(:name))
xml.tag!('contact:crID', @contact.creator.try(:registrar)) xml.tag!('contact:crID', @contact.creator.try(:registrar))
xml.tag!('contact:crDate', @contact.created_at) xml.tag!('contact:crDate', @contact.created_at)
@ -18,18 +18,17 @@ xml.epp_head do
xml.tag!('contact:upID', @contact.updator.try(:registrar)) xml.tag!('contact:upID', @contact.updator.try(:registrar))
xml.tag!('contact:upDate', @contact.updated_at) xml.tag!('contact:upDate', @contact.updated_at)
end end
xml.tag!('contact:ident', @contact.ident, type: @contact.ident_type) xml.tag!('contact:ident', @contact.ident, type: @contact.ident_type, cc: @contact.ident_country_code)
xml.tag!('contact:trDate', '123') if false # xml.tag!('contact:trDate', '123') if false
if @owner if can? :view_password, @contact
xml.tag!('contact:authInfo') do xml.tag!('contact:authInfo') do
xml.tag!('contact:pw', @contact.auth_info) # Doc says we have to return this but is it necessary? xml.tag!('contact:pw', @contact.auth_info)
end end
end end
# statuses @contact.statuses.each do |status|
@contact.statuses.each do |cs| xml.tag!('contact:status', s: status.value)
xml.tag!('contact:status', s: cs.value)
end end
xml << render('/epp/contacts/disclosure_policy') # xml << render('/epp/contacts/disclosure_policy')
end end
end end

View file

@ -21,7 +21,7 @@
%span.icon-bar %span.icon-bar
%span.icon-bar %span.icon-bar
= link_to admin_dashboard_path, class: 'navbar-brand' do = link_to admin_dashboard_path, class: 'navbar-brand' do
= APP_CONFIG['app_name'] = ENV['app_name']
- if unstable_env.present? - if unstable_env.present?
.text-center .text-center
%small{style: 'color: #0074B3;'}= unstable_env %small{style: 'color: #0074B3;'}= unstable_env

View file

@ -1,10 +0,0 @@
#!/bin/bash
#
# For docker
#
# cd to Rails root directory
cd "$(dirname "$0")"; cd ..
bin/update-repo
bin/robot

View file

@ -16,14 +16,14 @@ export RAILS_ENV=test
cd "$(dirname "$0")"; cd .. cd "$(dirname "$0")"; cd ..
cp config/application-example.yml config/application.yml 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 bundle install
RAILS_ENV=test bundle exec rake db:drop RAILS_ENV=test bundle exec rake db:all:drop
RAILS_ENV=test bundle exec rake db:all:create RAILS_ENV=test bundle exec rake db:all:setup
RAILS_ENV=test bundle exec rake db:all:schema:load
RAILS_ENV=test bundle exec rake db:seed
RAILS_ENV=test bundle exec rake assets:precompile RAILS_ENV=test bundle exec rake assets:precompile
echo "GIT_LAST_COMMITS" echo "GIT_LAST_COMMITS"
@ -36,6 +36,10 @@ RCODE=$?
echo "END_OF_RUBOCOP_RESULTS" echo "END_OF_RUBOCOP_RESULTS"
echo "TEST_RESULTS" echo "TEST_RESULTS"
# basic test
# ROBOT=true bundle exec rake
# all tests with EPP
ROBOT=true bundle exec rake test ROBOT=true bundle exec rake test
TCODE=$? TCODE=$?
echo "END_OF_TEST_RESULTS" echo "END_OF_TEST_RESULTS"
@ -45,7 +49,7 @@ bundle exec bundle-audit update
bundle exec bundle-audit bundle exec bundle-audit
BCODE=$? BCODE=$?
BCODE=0 # tmp BCODE=0 # tmp
bundle exec brakeman bundle exec brakeman -q
echo "END_OF_SECURITY_RESULTS" echo "END_OF_SECURITY_RESULTS"
# update code review # update code review

View file

@ -1,27 +1,29 @@
defaults: &defaults # Be sure to restart your server when you modify settings.
app_name: .EE Registry
zonefile_export_dir: 'export/zonefiles'
# You can use `rake secret` to generate a secure secret key. app_name: .EE Registry
# Your secret key is used for verifying the integrity of signed cookies. zonefile_export_dir: 'export/zonefiles'
# 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
ca_cert_path: ca-cert-path-here
ca_key_path: ca-key-path-here
ca_key_password: ca-key-pass-phrase-here
development: # You can use `rake secret` to generate a secure secret key.
<<: *defaults # 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 admin server, you can leave those empty for when running EPP server:
openssl_config_path: '/etc/ssl/openssl.cnf'
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'
# Used only by EPP server, you can leave it empty when running admin server:
webclient_ip: '127.0.0.1'
# autotest config overwrites
test: 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

19
config/database-robot.yml Normal file
View file

@ -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

View file

@ -0,0 +1,19 @@
default: &default
host: localhost
adapter: postgresql
encoding: unicode
pool: 5
username: postgres
password:
test:
<<: *default
database: registry_test
whois_test:
<<: *default
database: registry_whois_test
api_log_test:
<<: *default
database: registry_api_log_test

View file

@ -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']

View file

@ -4,7 +4,7 @@ Devise.setup do |config|
# The secret key used by Devise. Devise uses this key to generate # The secret key used by Devise. Devise uses this key to generate
# random tokens. Changing this key will render invalid all existing # random tokens. Changing this key will render invalid all existing
# confirmation, reset password and unlock tokens in the database. # confirmation, reset password and unlock tokens in the database.
config.secret_key = APP_CONFIG['devise_secret'] config.secret_key = ENV['devise_secret']
# ==> Mailer Configuration # ==> Mailer Configuration
# Configure the e-mail address which will be shown in Devise::Mailer, # Configure the e-mail address which will be shown in Devise::Mailer,

View file

@ -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)

View file

@ -1,4 +1,5 @@
if 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_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? Setting.disclosure_org_name = true if Setting.disclosure_org_name.nil?

View file

@ -0,0 +1 @@
Registry::Application.config.secret_token = ENV['secret_key_base']

View file

@ -1,24 +1,3 @@
# Files in the config/locales directory are used for internationalization
# and are automatically loaded by Rails. If you want to use locales other
# than English, add the necessary files in this directory.
#
# To use the locales, use `I18n.t`:
#
# I18n.t 'hello'
#
# In views, this is aliased to just `t`:
#
# <%= t('hello') %>
#
# To use a different locale, set it with `I18n.locale`:
#
# I18n.locale = :es
#
# This would use the information in config/locales/es.yml.
#
# To learn more, please read the Rails Internationalization guide
# available at http://guides.rubyonrails.org/i18n.html.
en: en:
views: views:
pagination: pagination:
@ -52,7 +31,6 @@ en:
activerecord: activerecord:
errors: errors:
models: models:
contact: contact:
attributes: attributes:
code: code:
@ -67,6 +45,8 @@ en:
invalid: "Email is invalid" invalid: "Email is invalid"
ident: ident:
blank: "Required parameter missing - ident" blank: "Required parameter missing - ident"
invalid_EE_identity_format: "Ident not in valid Estonian identity format."
invalid_birthday_format: "Ident not in valid birthady format, should be YYYY-MM-DD"
domains: domains:
exist: 'Object association prohibits operation' exist: 'Object association prohibits operation'
@ -258,7 +238,7 @@ en:
invalid_type: 'PostalInfo type is invalid' invalid_type: 'PostalInfo type is invalid'
unimplemented_command: 'Unimplemented command' unimplemented_command: 'Unimplemented command'
domain_exists_but_belongs_to_other_registrar: 'Domain exists but belongs to other registrar' domain_exists_but_belongs_to_other_registrar: 'Domain exists but belongs to other registrar'
required_attribute_missing: Required attributes missing
code: 'Code' code: 'Code'
value: 'Value' value: 'Value'
@ -321,7 +301,7 @@ en:
domain_status_prohibits_deleting: 'Domain status prohibits deleting' domain_status_prohibits_deleting: 'Domain status prohibits deleting'
domain_deleted: 'Domain deleted!' domain_deleted: 'Domain deleted!'
failed_to_delete_domain: 'Failed to delete domain!' failed_to_delete_domain: 'Failed to delete domain!'
email: 'Email' email: 'E-mail'
fax: 'Fax' fax: 'Fax'
contact_details: 'Contact details' contact_details: 'Contact details'
ident: 'Ident' ident: 'Ident'
@ -330,8 +310,8 @@ en:
country: 'Country' country: 'Country'
city: 'City' city: 'City'
street: 'Street' street: 'Street'
zip: 'Zip' zip: 'Postcode'
org_name: 'Organisation name' org_name: 'Org name'
failed_to_add_domain: 'Failed to add domain!' failed_to_add_domain: 'Failed to add domain!'
domain_added: 'Domain added!' domain_added: 'Domain added!'
new_contact: 'New contact' new_contact: 'New contact'
@ -502,3 +482,11 @@ en:
download: 'Download' download: 'Download'
failed_to_create_certificate: 'Failed to create certificate!' failed_to_create_certificate: 'Failed to create certificate!'
registrant_not_found: 'Registrant not found' registrant_not_found: 'Registrant not found'
failed_to_revoke_certificate: 'Failed to revoke certificate!'
contact_code: Contact code
upload_csr: 'Upload CSR'
signature_algorithm: 'Signature algorithm'
version: 'Version'
sign_this_request: 'Sign this request'
revoke_this_certificate: 'Revoke this certificate'
crt_revoked: 'CRT (revoked)'

View file

@ -3,6 +3,7 @@ require 'epp_constraint'
Rails.application.routes.draw do Rails.application.routes.draw do
namespace(:epp, defaults: { format: :xml }) do namespace(:epp, defaults: { format: :xml }) do
match 'session/:action', controller: 'sessions', via: :all match 'session/:action', controller: 'sessions', via: :all
match 'session/pki/:action', controller: 'sessions', via: :all
post 'command/:action', controller: 'domains', constraints: EppConstraint.new(:domain) post 'command/:action', controller: 'domains', constraints: EppConstraint.new(:domain)
post 'command/:action', controller: 'contacts', constraints: EppConstraint.new(:contact) post 'command/:action', controller: 'contacts', constraints: EppConstraint.new(:contact)
@ -47,11 +48,15 @@ Rails.application.routes.draw do
resources :admin_users resources :admin_users
resources :api_users do resources :api_users do
resources :certificates do
member do member do
post 'sign'
post 'revoke'
get 'download_csr' get 'download_csr'
get 'download_crt' get 'download_crt'
end end
end end
end
resources :delayed_jobs resources :delayed_jobs

View file

@ -0,0 +1,5 @@
class AddStateToAddress < ActiveRecord::Migration
def change
add_column :addresses, :state, :string
end
end

View file

@ -0,0 +1,5 @@
class AddCountryCodeIdent < ActiveRecord::Migration
def change
add_column :contacts, :ident_country_code, :string
end
end

View file

@ -0,0 +1,5 @@
class AddIndexForContactCode < ActiveRecord::Migration
def change
add_index :contacts, :code
end
end

View file

@ -0,0 +1,29 @@
class CreateCertificates < ActiveRecord::Migration
def change
create_table :certificates do |t|
t.integer :api_user_id
t.text :csr
t.text :crt
t.string :creator_str
t.string :updator_str
t.timestamps
end
create_table :log_certificates do |t|
t.string "item_type", null: false
t.integer "item_id", null: false
t.string "event", null: false
t.string "whodunnit"
t.json "object"
t.json "object_changes"
t.datetime "created_at"
t.string "session"
t.json "children"
end
ApiUser.all.each do |x|
x.certificates << Certificate.new(crt: x.crt, csr: x.csr)
end
end
end

View file

@ -0,0 +1,5 @@
class ChangeApiUserDefaultValue < ActiveRecord::Migration
def change
change_column_default :users, :active, nil
end
end

View file

@ -0,0 +1,6 @@
class AddCodeToRegistrar < ActiveRecord::Migration
def change
add_column :registrars, :code, :string
add_index :registrars, :code
end
end

View file

@ -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(validate: false)
end
end
end

View file

@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20150213104014) do ActiveRecord::Schema.define(version: 20150303151224) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -29,6 +29,7 @@ ActiveRecord::Schema.define(version: 20150213104014) do
t.string "creator_str" t.string "creator_str"
t.string "updator_str" t.string "updator_str"
t.string "country_code" t.string "country_code"
t.string "state"
end end
create_table "api_users", force: :cascade do |t| create_table "api_users", force: :cascade do |t|
@ -52,6 +53,16 @@ ActiveRecord::Schema.define(version: 20150213104014) do
add_index "cached_nameservers", ["hostname", "ipv4", "ipv6"], name: "index_cached_nameservers_on_hostname_and_ipv4_and_ipv6", unique: true, using: :btree add_index "cached_nameservers", ["hostname", "ipv4", "ipv6"], name: "index_cached_nameservers_on_hostname_and_ipv4_and_ipv6", unique: true, using: :btree
create_table "certificates", force: :cascade do |t|
t.integer "api_user_id"
t.text "csr"
t.text "crt"
t.string "creator_str"
t.string "updator_str"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "contact_disclosures", force: :cascade do |t| create_table "contact_disclosures", force: :cascade do |t|
t.integer "contact_id" t.integer "contact_id"
t.boolean "phone" t.boolean "phone"
@ -95,8 +106,11 @@ ActiveRecord::Schema.define(version: 20150213104014) do
t.integer "registrar_id" t.integer "registrar_id"
t.string "creator_str" t.string "creator_str"
t.string "updator_str" t.string "updator_str"
t.string "ident_country_code"
end end
add_index "contacts", ["code"], name: "index_contacts_on_code", using: :btree
create_table "countries", force: :cascade do |t| create_table "countries", force: :cascade do |t|
t.string "iso" t.string "iso"
t.string "name" t.string "name"
@ -271,6 +285,18 @@ ActiveRecord::Schema.define(version: 20150213104014) do
add_index "log_api_users", ["item_type", "item_id"], name: "index_log_api_users_on_item_type_and_item_id", using: :btree add_index "log_api_users", ["item_type", "item_id"], name: "index_log_api_users_on_item_type_and_item_id", using: :btree
add_index "log_api_users", ["whodunnit"], name: "index_log_api_users_on_whodunnit", using: :btree add_index "log_api_users", ["whodunnit"], name: "index_log_api_users_on_whodunnit", using: :btree
create_table "log_certificates", force: :cascade do |t|
t.string "item_type", null: false
t.integer "item_id", null: false
t.string "event", null: false
t.string "whodunnit"
t.json "object"
t.json "object_changes"
t.datetime "created_at"
t.string "session"
t.json "children"
end
create_table "log_contact_disclosures", force: :cascade do |t| create_table "log_contact_disclosures", force: :cascade do |t|
t.string "item_type", null: false t.string "item_type", null: false
t.integer "item_id", null: false t.integer "item_id", null: false
@ -585,8 +611,11 @@ ActiveRecord::Schema.define(version: 20150213104014) do
t.string "city" t.string "city"
t.string "street" t.string "street"
t.string "zip" t.string "zip"
t.string "code"
end end
add_index "registrars", ["code"], name: "index_registrars_on_code", using: :btree
create_table "reserved_domains", force: :cascade do |t| create_table "reserved_domains", force: :cascade do |t|
t.string "name" t.string "name"
t.datetime "created_at" t.datetime "created_at"
@ -626,7 +655,7 @@ ActiveRecord::Schema.define(version: 20150213104014) do
t.string "updator_str" t.string "updator_str"
t.string "country_code" t.string "country_code"
t.integer "registrar_id" t.integer "registrar_id"
t.boolean "active", default: false t.boolean "active"
t.text "csr" t.text "csr"
t.text "crt" t.text "crt"
t.string "type" t.string "type"

View file

@ -4,7 +4,10 @@
registrar1 = Registrar.where( registrar1 = Registrar.where(
name: 'Registrar First AS', name: 'Registrar First AS',
reg_no: '10300220', reg_no: '10300220',
address: 'Pärnu mnt 2, Tallinna linn, Harju maakond, 11415', street: 'Pärnu mnt 2',
city: 'Tallinn',
state: 'Harju maakond',
zip: '11415',
email: 'registrar1@example.com', email: 'registrar1@example.com',
country_code: 'EE' country_code: 'EE'
).first_or_create! ).first_or_create!
@ -19,7 +22,10 @@ ApiUser.where(
registrar2 = Registrar.where( registrar2 = Registrar.where(
name: 'Registrar Second AS', name: 'Registrar Second AS',
reg_no: '10529229', reg_no: '10529229',
address: 'Vabaduse pst 32, 11316 Tallinn', street: 'Vabaduse pst 32',
city: 'Tallinn',
state: 'Harju maakond',
zip: '11315',
email: 'registrar2@example.com', email: 'registrar2@example.com',
country_code: 'EE' country_code: 'EE'
).first_or_create! ).first_or_create!
@ -55,4 +61,26 @@ AdminUser.where(
country_code: 'EE' country_code: 'EE'
).first_or_create! ).first_or_create!
ZonefileSetting.where({
origin: 'ee',
ttl: 43200,
refresh: 3600,
retry: 900,
expire: 1209600,
minimum_ttl: 3600,
email: 'hostmaster.eestiinternet.ee',
master_nameserver: 'ns.tld.ee'
}).first_or_create!
ZonefileSetting.where({
origin: 'pri.ee',
ttl: 43200,
refresh: 3600,
retry: 900,
expire: 1209600,
minimum_ttl: 3600,
email: 'hostmaster.eestiinternet.ee',
master_nameserver: 'ns.tld.ee'
}).first_or_create!
AdminUser.update_all(roles: ['admin']) AdminUser.update_all(roles: ['admin'])

View file

@ -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) ### Debian setup
instead of Capistrano.
* [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. 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 # list all rake commands
rake -T db # list all database related commands rake -T db # list all database related commands
mina -T # list all mina deploy 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.

196
doc/certificates.md Normal file
View file

@ -0,0 +1,196 @@
Certificates setup
------------------
Guide to setup all registry/epp/repp, webclient and api user certificates.
There are three type of certificates:
* root cert (one time action using command line)
* webclient server cert (one time action using command line)
* api user cert (multiple actions through admin interface)
API users CSR are uploaded through registry admin interface for each API user.
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
sudo vi /etc/ssl/openssl.cnf
Make sure the following options are in place:
[ CA_default ]
# Where everything is kept
dir = /home/registry/registry/shared/ca # around line nr 42
crl_extensions = crl_ext # around line nr 71
# For the CA policy
[ policy_match ]
countryName = optional # around line nr 85
stateOrProvinceName = optional # around line nr 86
organizationName = optional # around line nr 87
organizationalUnitName = optional # around line nr 88
commonName = supplied # around line nr 89
emailAddress = optional # around line nr 90
[ usr_cert ]
# These extensions are added when 'ca' signs a request.
basicConstraints=CA:FALSE # around line nr 170
keyUsage = nonRepudiation, digitalSignature, keyEncipherment # around line nr 188
nsComment = "OpenSSL Generated Certificate" # around line nr 191
subjectKeyIdentifier=hash # around line nr 194
authorityKeyIdentifier=keyid,issuer # around line nr 195
[ v3_ca ]
# Extensions for a typical CA
subjectKeyIdentifier=hash # around line nr 232
authorityKeyIdentifier=keyid:always,issuer # around line nr 234
basicConstraints = CA:true # around line nr 240
keyUsage = cRLSign, keyCertSign # around line nr 245
Generate the root key and remember your password, you need it later in application.yml:
openssl genrsa -aes256 -out private/ca.key.pem 4096
Create root registry certificate (prompts for additional data and review days flag):
openssl req -new -x509 -days 3653 -key private/ca.key.pem -sha256 -extensions v3_ca -out certs/ca.crt.pem
chmod 444 certs/ca.crt.pem
Create a webclient key and CSR for accepting webclient request:
openssl genrsa -out private/webclient.key.pem 4096
chmod 400 private/webclient.key.pem
openssl req -sha256 -new -days 3653 -key private/webclient.key.pem -out csrs/webclient.csr.pem
Sign CSR and create certificate:
openssl ca -keyfile private/ca.key.pem -cert certs/ca.crt.pem -extensions usr_cert -notext -md sha256 -in csrs/webclient.csr.pem -days 3653 -out certs/webclient.crt.pem
chmod 444 certs/webclient.crt.pem
Create certificate revocation list (prompts for pass phrase):
openssl ca -keyfile private/ca.key.pem -cert certs/ca.crt.pem -gencrl -out crl/crl.pem
Configure registry registry/shared/config/application.yml to match the CA settings:
openssl_config_path: '/etc/ssl/openssl.cnf'
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'
### Registry EPP setup
Configure registry epp registry-epp/shared/config/application.yml:
webclient_ip: '54.154.91.240'
Configure EPP port 700 virtual host:
sudo vi /etc/apache2/sites-enabled/epp.conf
Replace this line:
SSLVerifyClient optional_no_ca
With these lines:
SSLVerifyClient require
SSLVerifyDepth 1
SSLCACertificateFile /home/registry/registry/shared/ca/certs/ca.crt.pem
SSLCARevocationFile /home/registry/registry/shared/ca/crl/crl.pem
# Uncomment this when upgrading to apache 2.4:
# SSLCARevocationCheck chain
RequestHeader set SSL_CLIENT_S_DN_CN "%{SSL_CLIENT_S_DN_CN}s"
Reload apache:
sudo a2enmod headers
sudo /etc/init.d/apache2 restart
### Webclient setup
Copy all registry/shared/ca directory to your webclient server if webclient is in different server,
otherwise just point everything to your registry/shared/ca directory.
Configure webclient/shared/config/application.yml to match the CA settings:
cert_path: '/home/webclient/webclient/shared/ca/certs/webclient.crt.pem'
key_path: '/home/webclient/webclient/shared/ca/private/webclient.key.pem'
Configure webclient virtual host:
sudo vi /etc/apache2/sites-enabled/webclient.conf
Add these lines:
SSLVerifyClient none
SSLVerifyDepth 1
SSLCACertificateFile /home/webclient/webclient/shared/ca/certs/ca.crt.pem
SSLCARevocationFile /home/webclient/webclient/shared/ca/crl/crl.pem
# Uncomment this when upgrading to apache 2.4:
# SSLCARevocationCheck chain
RequestHeader set SSL_CLIENT_S_DN_CN ""
<Location /sessions/pki>
SSLVerifyClient require
RequestHeader set SSL_CLIENT_S_DN_CN "%{SSL_CLIENT_S_DN_CN}s"
</Location>
Reload apache:
sudo a2enmod headers
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
---------------
In development environment it's convenient to set unique_subject option to false,
thus you can generate quickly as many certs as you wish.
In CA directory:
echo "unique_subject = no" > index.txt.attr

View file

@ -1,6 +1,6 @@
## Contact related functions ## Contact related functions
Please study official Cantact Mapping protocol: Please study official Contact Mapping protocol:
http://tools.ietf.org/html/rfc5733 http://tools.ietf.org/html/rfc5733
More info at http://en.wikipedia.org/wiki/Extensible_Provisioning_Protocol More info at http://en.wikipedia.org/wiki/Extensible_Provisioning_Protocol
@ -13,6 +13,7 @@ Contact Mapping protocol short version:
----------------------- ------- ----------------- ----------------------- ------- -----------------
<create> 1 <create> 1
<contact:create> 1 Attribute: xmlns:contact="urn:ietf:params:xml:ns:contact-1.0" <contact:create> 1 Attribute: xmlns:contact="urn:ietf:params:xml:ns:contact-1.0"
<contact:id> 0-1 Contact id, optional, generated automatically if missing
<contact:postalInfo> 1 Postal information container <contact:postalInfo> 1 Postal information container
<contact:name> 1 Full name of the contact <contact:name> 1 Full name of the contact
<contact:org> 0-1 Name of organization <contact:org> 0-1 Name of organization
@ -34,8 +35,6 @@ Contact Mapping protocol short version:
<eis:legalDocument> 1 Base64 encoded document <eis:legalDocument> 1 Base64 encoded document
Attribute: type="pdf/bdoc/ddoc/zip/rar/gz/tar/7z" Attribute: type="pdf/bdoc/ddoc/zip/rar/gz/tar/7z"
[EXAMPLE REQUEST AND RESPONSE](/doc/epp-examples.md#epp-contact-with-valid-user-create-command-successfully-creates-a-contact) [EXAMPLE REQUEST AND RESPONSE](/doc/epp-examples.md#epp-contact-with-valid-user-create-command-successfully-creates-a-contact)
### Contact update ### Contact update
@ -44,7 +43,7 @@ Contact Mapping protocol short version:
----------------------- ------- ----------------- ----------------------- ------- -----------------
<update> 1 <update> 1
<contact:update> 1 Attribute: xmlns:contact="urn:ietf:params:xml:ns:contact-1.0" <contact:update> 1 Attribute: xmlns:contact="urn:ietf:params:xml:ns:contact-1.0"
<contact:id> 1 contact id, required <contact:id> 1 Contact id, required
<contact:chg> 1 Change container <contact:chg> 1 Change container
<contact:postalInfo> 1 Postal information container <contact:postalInfo> 1 Postal information container
<contact:name> 0-1 Full name of the contact <contact:name> 0-1 Full name of the contact

114
doc/testing.md Normal file
View file

@ -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
<IfModule mod_epp.c>
Listen 701
<VirtualHost *: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
</VirtualHost>
</IfModule>
```
* 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
<IfModule mod_epp.c>
<Directory "/usr/lib/cgi-bin/epp">
Options ExecCGI
SetHandler cgi-script
</Directory>
Listen 1700
<VirtualHost *: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
<Location /epp/auth>
AuthType Basic
AuthName "EPP"
AuthUserFile /etc/apache2/htpasswd
require valid-user
</Location>
</VirtualHost>
</IfModule>
```
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

View file

@ -1,16 +1,14 @@
namespace :db do namespace :db do
def databases def other_databases
@db ||= ["api_log_#{Rails.env}", "whois_#{Rails.env}", "#{Rails.env}"] @db ||= ["api_log_#{Rails.env}", "whois_#{Rails.env}"]
end end
def schema_file(db) def schema_file(db)
case db case db
when databases.first when "api_log_#{Rails.env}"
'api_log_schema.rb' 'api_log_schema.rb'
when databases.second when "whois_#{Rails.env}"
'whois_schema.rb' 'whois_schema.rb'
when databases.third
'schema.rb'
end end
end end
@ -19,16 +17,51 @@ namespace :db do
task setup: [:environment] do task setup: [:environment] do
Rake::Task['db:all:create'].invoke Rake::Task['db:all:create'].invoke
Rake::Task['db:all:schema:load'].invoke Rake::Task['db:all:schema:load'].invoke
Rake::Task['db:seed'].invoke
ActiveRecord::Base.clear_all_connections!
ActiveRecord::Base.establish_connection(Rails.env.to_sym)
# puts "\n---------------------------- Import seed ----------------------------------------\n"
# Rake::Task['db:seed'].invoke
puts "\n All done!\n\n"
end end
desc 'Create all databases: registry, api_log and whois' desc 'Create all databases: registry, api_log and whois'
task create: [:environment] do task create: [:environment] do
databases.each do |name| puts "\n---------------------------- Create main database ----------------------------------------\n"
Rake::Task['db:create'].invoke
other_databases.each do |name|
begin begin
conf = ActiveRecord::Base.configurations puts "\n---------------------------- Create #{name} ----------------------------------------\n"
ActiveRecord::Base.clear_all_connections! ActiveRecord::Base.clear_all_connections!
ActiveRecord::Base.connection.create_database(conf[name]['database'], conf[name]) conf = ActiveRecord::Base.configurations
ActiveRecord::Base.connection.create_database(conf[name]['database'].to_sym, conf[name])
rescue => e
puts "\n#{e}"
end
end
end
desc 'Drop all databaseses: registry, api_log and whois'
task drop: [:environment] do
# just in case we allow only drop test, comment it out please for temp
return unless Rails.env.test?
Rake::Task['db:drop'].invoke
conf = ActiveRecord::Base.configurations
puts "#{conf[Rails.env]['database']} dropped"
other_databases.each do |name|
begin
ActiveRecord::Base.clear_all_connections!
ActiveRecord::Base.establish_connection(name.to_sym)
conf = ActiveRecord::Base.configurations
if ActiveRecord::Tasks::DatabaseTasks.drop(conf[name])
puts "#{conf[name]['database']} dropped"
else
puts "Didn't find database #{name}, no drop"
end
rescue => e rescue => e
puts "\n#{e}" puts "\n#{e}"
end end
@ -38,10 +71,14 @@ namespace :db do
namespace :schema do namespace :schema do
desc 'Schema load for all databases: registry, api_log and whois' desc 'Schema load for all databases: registry, api_log and whois'
task load: [:environment] do task load: [:environment] do
databases.each do |name| puts "\n---------------------------- Main schema load ----------------------------------------\n"
Rake::Task['db:schema:load'].invoke
other_databases.each do |name|
begin begin
puts "\n---------------------------- #{name} ----------------------------------------\n" puts "\n---------------------------- #{name} schema loaded ----------------------------------------\n"
ActiveRecord::Base.establish_connection(name) ActiveRecord::Base.clear_all_connections!
ActiveRecord::Base.establish_connection(name.to_sym)
if ActiveRecord::Base.connection.table_exists?('schema_migrations') if ActiveRecord::Base.connection.table_exists?('schema_migrations')
puts 'Found tables, skip schema load!' puts 'Found tables, skip schema load!'
else else
@ -55,7 +92,10 @@ namespace :db do
desc 'Schema load for all databases: registry, api_log and whois' desc 'Schema load for all databases: registry, api_log and whois'
task dump: [:environment] do task dump: [:environment] do
databases.each do |name| puts "\n---------------------------- Main schema load ----------------------------------------\n"
Rake::Task['db:schema:dump'].invoke
other_databases.each do |name|
begin begin
puts "\n---------------------------- #{name} ----------------------------------------\n" puts "\n---------------------------- #{name} ----------------------------------------\n"
filename = "#{Rails.root}/db/#{schema_file(name)}" filename = "#{Rails.root}/db/#{schema_file(name)}"

View file

@ -30,7 +30,7 @@ begin
end end
Rake::Task[:default].prerequisites.clear Rake::Task[:default].prerequisites.clear
task default: :test task default: 'test:other'
def test_against_server def test_against_server
_stdin, _stdout, _stderr, wait_thr = Open3.popen3('unicorn -E test -p 8989') _stdin, _stdout, _stderr, wait_thr = Open3.popen3('unicorn -E test -p 8989')

View file

@ -1,451 +1,441 @@
# require 'rails_helper' require 'rails_helper'
# describe 'EPP Contact', epp: true do describe 'EPP Contact', epp: true do
# before :all do before :all do
# create_settings create_settings
# create_disclosure_settings create_disclosure_settings
# @registrar1 = Fabricate(:registrar1) @registrar1 = Fabricate(:registrar1)
# @registrar2 = Fabricate(:registrar2) @registrar2 = Fabricate(:registrar2)
# @epp_xml = EppXml::Contact.new(cl_trid: 'ABC-12345') @epp_xml = EppXml::Contact.new(cl_trid: 'ABC-12345')
# Fabricate(:api_user, username: 'registrar1', registrar: @registrar1) Fabricate(:api_user, username: 'registrar1', registrar: @registrar1)
# Fabricate(:api_user, username: 'registrar2', registrar: @registrar2) Fabricate(:api_user, username: 'registrar2', registrar: @registrar2)
# login_as :registrar1 login_as :registrar1
# Contact.skip_callback(:create, :before, :generate_code) @contact = Fabricate(:contact, registrar: @registrar1)
# Contact.skip_callback(:create, :before, :generate_auth_info)
# end @legal_document = {
legalDocument: {
# after :all do value: 'JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0Zp==',
# Contact.set_callback(:create, :before, :generate_code) attrs: { type: 'pdf' }
# Contact.set_callback(:create, :before, :generate_auth_info) }
# end }
end
# context 'with valid user' do
# context 'create command' do context 'with valid user' do
# it 'fails if request xml is missing' do context 'create command' do
# xml = @epp_xml.create def create_request(overwrites = {})
# response = epp_plain_request(xml, :xml) defaults = {
# response[:results][0][:msg].should == 'Command syntax error' postalInfo: {
# response[:results][0][:result_code].should == '2001' name: { value: 'John Doe' },
addr: {
# response[:results].count.should == 1 street: { value: '123 Example' },
# end city: { value: 'Tallinn' },
cc: { value: 'EE' }
# it 'fails if request xml is missing' do }
# xml = @epp_xml.create( },
# postalInfo: { addr: { value: nil } } voice: { value: '+372.1234567' },
# ) email: { value: 'test@example.example' },
# response = epp_plain_request(xml, :xml) ident: { value: '37605030299', attrs: { type: 'priv', cc: 'EE' } }
# response[:results][0][:msg].should == 'Required parameter missing: name' }
# response[:results][1][:msg].should == 'Required parameter missing: city' create_xml = @epp_xml.create(defaults.deep_merge(overwrites), @legal_document)
# response[:results][2][:msg].should == 'Required parameter missing: cc' epp_plain_request(create_xml, :xml)
# response[:results][3][:msg].should == 'Required parameter missing: ident' end
# response[:results][4][:msg].should == 'Required parameter missing: voice'
# response[:results][5][:msg].should == 'Required parameter missing: email' it 'fails if request xml is missing' do
response = epp_plain_request(@epp_xml.create, :xml)
# response[:results][0][:result_code].should == '2003' response[:results][0][:msg].should ==
# response[:results][1][:result_code].should == '2003' 'Required parameter missing: create > create > postalInfo > name [name]'
# response[:results][2][:result_code].should == '2003' response[:results][1][:msg].should ==
# response[:results][3][:result_code].should == '2003' 'Required parameter missing: create > create > postalInfo > addr > city [city]'
# response[:results][4][:result_code].should == '2003' response[:results][2][:msg].should ==
# response[:results][5][:result_code].should == '2003' 'Required parameter missing: create > create > postalInfo > addr > cc [cc]'
response[:results][3][:msg].should ==
# response[:results].count.should == 6 'Required parameter missing: create > create > ident [ident]'
# end response[:results][4][:msg].should ==
'Required parameter missing: create > create > voice [voice]'
# it 'successfully saves ident type' do response[:results][5][:msg].should ==
# xml = { ident: { value: '1990-22-12', attrs: { type: 'birthday' } } } 'Required parameter missing: create > create > email [email]'
# epp_plain_request(create_contact_xml(xml), :xml) response[:results][6][:msg].should ==
'Required parameter missing: extension > extdata > legalDocument [legal_document]'
# Contact.last.ident_type.should == 'birthday'
# end response[:results][0][:result_code].should == '2003'
response[:results][1][:result_code].should == '2003'
# it 'successfully creates a contact' do response[:results][2][:result_code].should == '2003'
# response = epp_plain_request(create_contact_xml, :xml) response[:results][3][:result_code].should == '2003'
response[:results][4][:result_code].should == '2003'
# response[:msg].should == 'Command completed successfully' response[:results][5][:result_code].should == '2003'
# response[:result_code].should == '1000' response[:results][6][:result_code].should == '2003'
# @contact = Contact.last response[:results].count.should == 7
end
# @contact.registrar.should == @registrar1
# # registrar1.api_users.should include(@contact.created_by) it 'successfully creates a contact' do
# # @contact.updated_by_id.should == nil response = create_request
# @contact.ident.should == '37605030299'
# @contact.address.street.should == '123 Example' response[:msg].should == 'Command completed successfully'
response[:result_code].should == '1000'
# log = ApiLog::EppLog.last
# log.request_command.should == 'create' @contact = Contact.last
# log.request_object.should == 'contact'
# log.request_successful.should == true @contact.registrar.should == @registrar1
# log.api_user_name.should == '1-api-registrar1' @registrar1.api_users.should include(@contact.creator)
# log.api_user_registrar.should == 'registrar1' @contact.ident.should == '37605030299'
# end @contact.address.street.should == '123 Example'
@contact.legal_documents.count.should == 1
# it 'successfully adds registrar' do
# response = epp_plain_request(create_contact_xml, :xml) log = ApiLog::EppLog.last
log.request_command.should == 'create'
# response[:msg].should == 'Command completed successfully' log.request_object.should == 'contact'
# response[:result_code].should == '1000' log.request_successful.should == true
log.api_user_name.should == '1-api-registrar1'
# Contact.last.registrar.should == @registrar1 log.api_user_registrar.should == 'registrar1'
# end end
# it 'returns result data upon success' do it 'successfully saves ident type' do
# response = epp_plain_request(create_contact_xml, :xml) response = create_request(
{ ident: { value: '1990-22-12', attrs: { type: 'birthday' } } }
# response[:msg].should == 'Command completed successfully' )
# response[:result_code].should == '1000'
response[:msg].should == 'Command completed successfully'
# id = response[:parsed].css('resData creData id').first response[:result_code].should == '1000'
# cr_date = response[:parsed].css('resData creData crDate').first
Contact.last.ident_type.should == 'birthday'
# id.text.length.should == 8 end
# # 5 seconds for what-ever weird lag reasons might happen
# cr_date.text.to_time.should be_within(5).of(Time.now) it 'successfully adds registrar' do
# end response = create_request
# it 'creates disclosure data' do response[:msg].should == 'Command completed successfully'
# xml = { response[:result_code].should == '1000'
# disclose: { value: {
# voice: { value: '' }, Contact.last.registrar.should == @registrar1
# addr: { value: '' }, end
# name: { value: '' },
# org_name: { value: '' }, it 'returns result data upon success' do
# email: { value: '' }, response = create_request
# fax: { value: '' }
# }, attrs: { flag: '1' } response[:msg].should == 'Command completed successfully'
# } response[:result_code].should == '1000'
# }
id = response[:parsed].css('resData creData id').first
# response = epp_plain_request(create_contact_xml(xml), :xml) cr_date = response[:parsed].css('resData creData crDate').first
# response[:result_code].should == '1000'
id.text.length.should == 8
# @contact = Contact.last # 5 seconds for what-ever weird lag reasons might happen
# @contact.disclosure.name.should == true cr_date.text.to_time.should be_within(5).of(Time.now)
# @contact.disclosure.org_name.should == true end
# @contact.disclosure.phone.should == true
# @contact.disclosure.fax.should == true it 'successfully saves custom code' do
# @contact.disclosure.email.should == true response = create_request(
# @contact.disclosure.address.should == true { id: { value: '12345' } }
# end )
# it 'creates disclosure data merging with defaults' do response[:msg].should == 'Command completed successfully'
# xml = { response[:result_code].should == '1000'
# disclose: { value: {
# voice: { value: '' }, Contact.last.code.should == 'registrar1:12345'
# addr: { value: '' } end
# }, attrs: { flag: '1' } end
# }
# } context 'update command' do
before :all do
# response = epp_plain_request(create_contact_xml(xml), :xml) @contact =
# response[:result_code].should == '1000' Fabricate(
:contact,
# @contact = Contact.last registrar: @registrar1,
# @contact.disclosure.name.should == nil email: 'not_updated@test.test',
# @contact.disclosure.org_name.should == nil code: 'sh8013'
# @contact.disclosure.phone.should == true )
# @contact.disclosure.fax.should == nil end
# @contact.disclosure.email.should == nil
# @contact.disclosure.address.should == true def update_request(overwrites = {})
# end defaults = {
# end id: { value: 'asd123123er' },
authInfo: { pw: { value: 'password' } },
# context 'update command' do chg: {
# before :all do postalInfo: {
# @contact = name: { value: 'John Doe Edited' }
# Fabricate( },
# :contact, voice: { value: '+372.7654321' },
# # created_by_id: 1, email: { value: 'edited@example.example' },
# registrar: @registrar1, disclose: {
# email: 'not_updated@test.test', value: {
# code: 'sh8013', voice: { value: '' },
# auth_info: 'password' email: { value: '' }
# ) }, attrs: { flag: '0' }
# end }
}
# it 'fails if request is invalid' do }
# xml = @epp_xml.update update_xml = @epp_xml.update(defaults.deep_merge(overwrites), @legal_document)
# response = epp_plain_request(xml, :xml) # epp_request('contacts/update_missing_attr.xml') epp_plain_request(update_xml, :xml)
end
# response[:results][0][:result_code].should == '2003'
# response[:results][0][:msg].should == 'Required parameter missing: add, rem or chg' it 'fails if request is invalid' do
# response[:results][1][:result_code].should == '2003' response = epp_plain_request(@epp_xml.update, :xml)
# response[:results][1][:msg].should == 'Required parameter missing: id'
# response[:results].count.should == 2 response[:results][0][:msg].should ==
# end 'Required parameter missing: add, rem or chg'
response[:results][0][:result_code].should == '2003'
# it 'fails with wrong authentication info' do response[:results][1][:msg].should ==
# login_as :registrar2 do 'Required parameter missing: update > update > id [id]'
# response = epp_plain_request(update_contact_xml({ id: { value: 'sh8013' } }), :xml) response[:results][1][:result_code].should == '2003'
# expect(response[:msg]).to eq('Authorization error') response[:results][2][:msg].should ==
# expect(response[:result_code]).to eq('2201') 'Required parameter missing: update > update > authInfo > pw [pw]'
# end response[:results][2][:result_code].should == '2003'
# end response[:results][3][:msg].should ==
'Required parameter missing: extension > extdata > legalDocument [legal_document]'
# it 'is succesful' do response[:results][3][:result_code].should == '2003'
# response = epp_plain_request(update_contact_xml({ id: { value: 'sh8013' } }), :xml) response[:results].count.should == 4
end
# response[:msg].should == 'Command completed successfully'
# @contact.reload it 'returns error if obj doesnt exist' do
# @contact.name.should == 'John Doe Edited' response = update_request({ id: { value: 'not-exists' } })
# @contact.email.should == 'edited@example.example' response[:msg].should == 'Object does not exist'
# end response[:result_code].should == '2303'
response[:results].count.should == 1
# it 'returns phone and email error' do end
# xml = {
# id: { value: 'sh8013' }, it 'is succesful' do
# chg: { response = update_request({ id: { value: 'sh8013' } })
# voice: { value: '123213' },
# email: { value: 'aaa' } response[:msg].should == 'Command completed successfully'
# } @contact.reload
# } @contact.name.should == 'John Doe Edited'
@contact.email.should == 'edited@example.example'
# response = epp_plain_request(update_contact_xml(xml), :xml) end
# response[:results][0][:msg].should == 'Phone nr is invalid' it 'fails with wrong authentication info' do
# response[:results][0][:result_code].should == '2005' login_as :registrar2 do
response = update_request({ id: { value: 'sh8013' } })
# response[:results][1][:msg].should == 'Email is invalid' response[:msg].should == 'Authorization error'
# response[:results][1][:result_code].should == '2005' response[:result_code].should == '2201'
# end end
end
# it 'updates disclosure items' do
# Fabricate( it 'returns phone and email error' do
# :contact, response = update_request({
# code: 'sh8013disclosure', id: { value: 'sh8013' },
# auth_info: '2fooBAR', chg: {
# registrar: @registrar1, voice: { value: '123213' },
# # created_by_id: ApiUser.first.id, email: { value: 'wrong' }
# disclosure: Fabricate(:contact_disclosure, phone: true, email: true)) }
})
# xml = {
# id: { value: 'sh8013disclosure' }, response[:results][0][:msg].should == 'Phone nr is invalid [phone]'
# authInfo: { pw: { value: '2fooBAR' } } response[:results][0][:result_code].should == '2005'
# } response[:results][1][:msg].should == 'Email is invalid [email]'
# @response = epp_plain_request(update_contact_xml(xml), :xml) response[:results][1][:result_code].should == '2005'
end
# @response[:results][0][:msg].should == 'Command completed successfully'
# @response[:results][0][:result_code].should == '1000' it 'should not update code with custom string' do
response = update_request(
# Contact.last.disclosure.phone.should == false id: { value: 'sh8013' },
# Contact.last.disclosure.email.should == false chg: {
# end id: { value: 'notpossibletoupdate' }
# end }
)
# context 'delete command' do
# it 'fails if request is invalid' do response[:msg].should == 'Object does not exist'
# xml = @epp_xml.delete({ uid: { value: '23123' } }) response[:result_code].should == '2303'
# response = epp_plain_request(xml, :xml)
@contact.reload.code.should == 'sh8013'
# response[:results][0][:msg].should == 'Required parameter missing: id' end
# response[:results][0][:result_code].should == '2003' end
# response[:results].count.should == 1
# end context 'delete command' do
before do
# it 'deletes contact' do @contact = Fabricate(:contact, registrar: @registrar1)
# @contact_deleted = end
# # Fabricate(:contact, code: 'dwa1234', created_by_id: ApiUser.first.id, registrar: registrar1)
# Fabricate(:contact, code: 'dwa1234', registrar: @registrar1) def delete_request(overwrites = {})
defaults = {
# response = epp_plain_request(delete_contact_xml({ id: { value: 'dwa1234' } }), :xml) id: { value: @contact.code },
# response[:msg].should == 'Command completed successfully' authInfo: { pw: { value: @contact.auth_info } }
# response[:result_code].should == '1000' }
# response[:clTRID].should == 'ABC-12345' delete_xml = @epp_xml.delete(defaults.deep_merge(overwrites), @legal_document)
epp_plain_request(delete_xml, :xml)
# Contact.find_by_id(@contact_deleted.id).should == nil end
# end
it 'fails if request is invalid' do
# it 'returns error if obj doesnt exist' do response = epp_plain_request(@epp_xml.delete, :xml)
# response = epp_plain_request(delete_contact_xml, :xml)
# response[:msg].should == 'Object does not exist' response[:results][0][:msg].should ==
# response[:result_code].should == '2303' 'Required parameter missing: delete > delete > id [id]'
# end response[:results][0][:result_code].should == '2003'
response[:results][1][:msg].should ==
# it 'fails if contact has associated domain' do 'Required parameter missing: delete > delete > authInfo > pw [pw]'
# Fabricate( response[:results][1][:result_code].should == '2003'
# :domain, response[:results][2][:msg].should ==
# registrar: @registrar1, 'Required parameter missing: extension > extdata > legalDocument [legal_document]'
# owner_contact: Fabricate( response[:results][2][:result_code].should == '2003'
# :contact, response[:results].count.should == 3
# code: 'dwa1234', end
# # created_by_id: registrar1.id,
# registrar: @registrar1) it 'returns error if obj doesnt exist' do
# ) response = delete_request({ id: { value: 'not-exists' } })
# Domain.last.owner_contact.address.present?.should == true response[:msg].should == 'Object does not exist'
# response = epp_plain_request(delete_contact_xml({ id: { value: 'dwa1234' } }), :xml) response[:result_code].should == '2303'
response[:results].count.should == 1
# response[:msg].should == 'Object association prohibits operation' end
# response[:result_code].should == '2305'
it 'deletes contact' do
# Domain.last.owner_contact.present?.should == true response = delete_request
# end response[:msg].should == 'Command completed successfully'
# end response[:result_code].should == '1000'
response[:clTRID].should == 'ABC-12345'
# context 'check command' do
# it 'fails if request is invalid' do Contact.find_by_id(@contact.id).should == nil
# xml = @epp_xml.check({ uid: { value: '123asde' } }) end
# response = epp_plain_request(xml, :xml)
it 'fails if contact has associated domain' do
# response[:results][0][:msg].should == 'Required parameter missing: id' @domain = Fabricate(:domain, registrar: @registrar1, owner_contact: @contact)
# response[:results][0][:result_code].should == '2003' @domain.owner_contact.address.present?.should == true
# response[:results].count.should == 1
# end response = delete_request
response[:msg].should == 'Object association prohibits operation [domains]'
# it 'returns info about contact availability' do response[:result_code].should == '2305'
# Fabricate(:contact, code: 'check-1234') response[:results].count.should == 1
# response = epp_plain_request(check_multiple_contacts_xml, :xml) @domain.owner_contact.present?.should == true
end
# response[:msg].should == 'Command completed successfully'
# response[:result_code].should == '1000' it 'fails with wrong authentication info' do
# ids = response[:parsed].css('resData chkData id') login_as :registrar2 do
response = delete_request
# ids[0].attributes['avail'].text.should == '0' response[:msg].should == 'Authorization error'
# ids[1].attributes['avail'].text.should == '1' response[:result_code].should == '2201'
response[:results].count.should == 1
# ids[0].text.should == 'check-1234' end
# ids[1].text.should == 'check-4321' end
# end end
# end
context 'check command' do
# # context 'info command' do def check_request(overwrites = {})
# # before :all do defaults = {
# # @registrar1_contact = Fabricate(:contact, code: 'info-4444', registrar: @registrar1, id: { value: @contact.code },
# # name: 'Johnny Awesome', address: Fabricate(:address)) authInfo: { pw: { value: @contact.auth_info } }
# # end }
xml = @epp_xml.check(defaults.deep_merge(overwrites))
# # fit 'return info about contact' do epp_plain_request(xml, :xml)
# # login_as :registrar2 do end
# # xml = @epp_xml.info(id: { value: @registrar1_contact.code })
# # response = epp_plain_request(xml, :xml) it 'fails if request is invalid' do
# # response[:msg].should == 'Command completed successfully' response = epp_plain_request(@epp_xml.check, :xml)
# # response[:result_code].should == '1000'
response[:results][0][:msg].should == 'Required parameter missing: check > check > id [id]'
# # contact = response[:parsed].css('resData chkData') response[:results][0][:result_code].should == '2003'
# # contact.css('name').first.text.should == 'Johnny Awesome' response[:results].count.should == 1
# # end end
# # end
it 'returns info about contact availability' do
# # it 'fails if request invalid' do Fabricate(:contact, code: 'check-1234')
# # response = epp_plain_request(@epp_xml.info({ wrongid: { value: '123123' } }), :xml)
# # response[:results][0][:msg].should == 'Required parameter missing: id' response = epp_plain_request(check_multiple_contacts_xml, :xml)
# # response[:results][0][:result_code].should == '2003'
# # response[:results].count.should == 1 response[:msg].should == 'Command completed successfully'
# # end response[:result_code].should == '1000'
ids = response[:parsed].css('resData chkData id')
# # it 'returns error when object does not exist' do
# # response = epp_plain_request(info_contact_xml({ id: { value: 'no-contact' } }), :xml) ids[0].attributes['avail'].text.should == '0'
# # response[:msg].should == 'Object does not exist' ids[1].attributes['avail'].text.should == '1'
# # response[:result_code].should == '2303'
# # response[:results][0][:value].should == 'no-contact' ids[0].text.should == 'check-1234'
# # end ids[1].text.should == 'check-4321'
end
# # # it 'returns auth error for non-owner with wrong password' do end
# # # @contact = Fabricate(:contact,
# # # registrar: registrar2, code: 'info-4444', name: 'Johnny Awesome', auth_info: 'asde', context 'info command' do
# # # address: Fabricate(:address), disclosure: Fabricate(:contact_disclosure, name: false)) def info_request(overwrites = {})
defaults = {
# # # xml = @epp_xml.info({ id: { value: @contact.code }, authInfo: { pw: { value: 'asdesde' } } }) id: { value: @contact.code },
# # # response = epp_plain_request(xml, :xml, :registrar1) authInfo: { pw: { value: @contact.auth_info } }
}
# # # expect(response[:result_code]).to eq('2200') xml = @epp_xml.info(defaults.deep_merge(overwrites))
# # # expect(response[:msg]).to eq('Authentication error') epp_plain_request(xml, :xml)
# # # end end
# # context 'about disclose' do it 'fails if request invalid' do
# # it 'discloses items with wrong password when queried by owner' do response = epp_plain_request(@epp_xml.info, :xml)
# # @contact = Fabricate(:contact, response[:results][0][:msg].should ==
# # registrar: registrar1, code: 'info-4444', 'Required parameter missing: info > info > id [id]'
# # name: 'Johnny Awesome', auth_info: 'asde', response[:results][0][:result_code].should == '2003'
# # address: Fabricate(:address), disclosure: Fabricate(:contact_disclosure, name: false)) response[:results].count.should == 1
end
# # xml = @epp_xml.info({ id: { value: @contact.code } })
# # login_as :registrar1 do it 'returns error when object does not exist' do
# # response = epp_plain_request(xml, :xml) response = info_request({ id: { value: 'no-contact' } })
# # contact = response[:parsed].css('resData chkData') response[:msg].should == 'Object does not exist'
response[:result_code].should == '2303'
# # expect(response[:result_code]).to eq('1000') response[:results][0][:value].should == 'no-contact'
# # expect(response[:msg]).to eq('Command completed successfully') response[:results].count.should == 1
# # expect(contact.css('name').first.text).to eq('Johnny Awesome') end
# # end
# # end it 'return info about contact' do
@registrar1_contact = Fabricate(
# # it 'doesn\'t disclose items to non-owner with right password' do :contact, code: 'info-4444', registrar: @registrar1,
# # @contact = Fabricate(:contact, registrar: registrar2, code: 'info-4444', name: 'Johnny Awesome', address: Fabricate(:address))
# # name: 'Johnny Awesome', auth_info: 'password',
# # address: Fabricate(:address), disclosure: Fabricate(:contact_disclosure, name: false)) response = info_request({ id: { value: @registrar1_contact.code } })
response[:msg].should == 'Command completed successfully'
# # xml = @epp_xml.info({ id: { value: @contact.code }, authInfo: { pw: { value: 'password' } } }) response[:result_code].should == '1000'
# # response = epp_plain_request(xml, :xml, :registrar1)
# # contact = response[:parsed].css('resData chkData') contact = response[:parsed].css('resData chkData')
contact.css('name').first.text.should == 'Johnny Awesome'
# # expect(response[:result_code]).to eq('1000') end
# # expect(response[:msg]).to eq('Command completed successfully')
# # expect(contact.css('chkData postalInfo name').first).to eq(nil) it 'returns no authorization error for wrong password when owner' do
# # end response = info_request({ authInfo: { pw: { value: 'wrong-pw' } } })
# # it 'discloses items to owner' do response[:msg].should == 'Command completed successfully'
# # @contact = Fabricate(:contact, registrar: registrar1, code: 'info-4444', name: 'Johnny Awesome', response[:result_code].should == '1000'
# # auth_info: 'password', response[:results].count.should == 1
# # address: Fabricate(:address), disclosure: Fabricate(:contact_disclosure, name: false)) end
# # xml = @epp_xml.info({ id: { value: @contact.code } }) it 'returns no authorization error for wrong user but correct pw' do
# # response = epp_plain_request(xml, :xml, :registrar1) login_as :registrar2 do
# # contact = response[:parsed].css('resData chkData') response = info_request
# # expect(response[:result_code]).to eq('1000') response[:msg].should == 'Command completed successfully'
# # expect(response[:msg]).to eq('Command completed successfully') response[:result_code].should == '1000'
# # expect(contact.css('name').first.text).to eq('Johnny Awesome') response[:results].count.should == 1
# # end end
end
# # it 'doesn\'t disclose private elements' do
# # Fabricate(:contact, code: 'info-4444', auth_info: '2fooBAR', registrar: registrar2, it 'returns authorization error for wrong user and wrong pw' do
# # disclosure: Fabricate(:contact_disclosure, name: true, email: false, phone: false)) login_as :registrar2 do
response = info_request({ authInfo: { pw: { value: 'wrong-pw' } } })
# # xml = @epp_xml.info({ id: { value: 'info-4444' }, authInfo: { pw: { value: '2fooBAR' } } }) response[:msg].should == 'Authorization error'
response[:result_code].should == '2201'
# # response = epp_plain_request(xml, :xml, :registrar1) response[:results].count.should == 1
# # contact = response[:parsed].css('resData chkData') end
end
# # expect(response[:result_code]).to eq('1000') end
# # expect(contact.css('chkData phone')).to eq(contact.css('chkData disclose phone')) context 'renew command' do
# # expect(contact.css('chkData phone').count).to eq(1) it 'returns 2101-unimplemented command' do
# # expect(contact.css('chkData email')).to eq(contact.css('chkData disclose email')) response = epp_plain_request('contacts/renew.xml')
# # expect(contact.css('chkData email').count).to eq(1)
# # expect(contact.css('postalInfo name').present?).to be(true) response[:msg].should == 'Unimplemented command'
# # end response[:result_code].should == '2101'
# # end end
end
# # it 'does not display unassociated object without password' do end
# # xml = @epp_xml.info(id: { value: @registrar1_contact.code })
# # response = epp_plain_request(xml, :xml, :registrar2) def check_multiple_contacts_xml
# # expect(response[:result_code]).to eq('2003') '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
# # expect(response[:msg]).to eq('Required parameter missing: pw') <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
# # end <command>
<check>
# # it 'does not display unassociated object with wrong password' do <contact:check
# # login_as :registrar2 xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
# # xml = @epp_xml.info(id: { value: @registrar1_contact.code }, <contact:id>check-1234</contact:id>
# # authInfo: { pw: { value: 'wrong-pw' } }) <contact:id>check-4321</contact:id>
# # response = epp_plain_request(xml, :xml) </contact:check>
</check>
# # response[:msg].should == 'Authentication error' <clTRID>ABC-12345</clTRID>
# # response[:result_code].should == '2200' </command>
# # end </epp>'
# # end end
end
# context 'renew command' do
# it 'returns 2101-unimplemented command' do
# response = epp_plain_request('contacts/renew.xml')
# response[:msg].should == 'Unimplemented command'
# response[:result_code].should == '2101'
# end
# end
# end
# end

View file

@ -11,12 +11,10 @@ describe 'EPP Domain', epp: true do
login_as :registrar1 login_as :registrar1
Contact.skip_callback(:create, :before, :generate_code)
Fabricate(:contact, code: 'citizen_1234') Fabricate(:contact, code: 'citizen_1234')
Fabricate(:contact, code: 'sh8013') Fabricate(:contact, code: 'sh8013')
Fabricate(:contact, code: 'sh801333') Fabricate(:contact, code: 'sh801333')
Fabricate(:contact, code: 'juridical_1234', ident_type: 'ico') Fabricate(:contact, code: 'juridical_1234', ident_type: 'bic')
Fabricate(:reserved_domain) Fabricate(:reserved_domain)
@uniq_no = proc { @i ||= 0; @i += 1 } @uniq_no = proc { @i ||= 0; @i += 1 }
@ -61,16 +59,20 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:results][0][:result_code].should == '2003' 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][: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][: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][: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 end
context 'with citizen as an owner' do context 'with citizen as an owner' do
@ -169,7 +171,7 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:result_code].should == '2306' response[:result_code].should == '2306'
response[:msg].should == 'IPv4 is missing' response[:msg].should == 'IPv4 is missing [ipv4]'
end end
# it 'does not create duplicate domain' do # it 'does not create duplicate domain' do
@ -191,7 +193,7 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:result_code].should == '2302' 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' response[:clTRID].should == 'ABC-12345'
end end
@ -200,14 +202,23 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:results][0][:result_code].should == '2003' 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 end
it 'does not create domain without nameservers' do it 'does not create domain without nameservers' do
xml = domain_create_xml(ns: []) xml = domain_create_xml(ns: [])
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:result_code].should == '2003'
response[:msg].should == 'Required parameter missing: create > create > ns > hostAttr' response[:results][0][:msg].should ==
'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 [host_attr]'
response[:results][1][:result_code].should == '2003'
response[:results].count.should == 2
end end
it 'does not create domain with too many nameservers' do it 'does not create domain with too many nameservers' do
@ -226,7 +237,7 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:result_code].should == '2004' 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 end
it 'returns error when invalid nameservers are present' do it 'returns error when invalid nameservers are present' do
@ -246,8 +257,8 @@ describe 'EPP Domain', epp: true do
}) })
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:msg].should == 'Hostname is invalid [hostname]'
response[:result_code].should == '2005' response[:result_code].should == '2005'
response[:msg].should == 'Hostname is invalid'
end end
it 'checks hostAttr presence' do it 'checks hostAttr presence' do
@ -263,8 +274,8 @@ describe 'EPP Domain', epp: true do
}) })
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:msg].should == 'Required parameter missing: create > create > ns > hostAttr [host_attr]'
response[:result_code].should == '2003' response[:result_code].should == '2003'
response[:msg].should == 'Required parameter missing: create > create > ns > hostAttr'
end end
it 'creates domain with nameservers with ips' do it 'creates domain with nameservers with ips' do
@ -280,10 +291,10 @@ describe 'EPP Domain', epp: true do
nameserver_count = Nameserver.count nameserver_count = Nameserver.count
response = epp_plain_request(domain_create_with_invalid_ns_ip_xml, :xml) response = epp_plain_request(domain_create_with_invalid_ns_ip_xml, :xml)
response[:results][0][:result_code].should == '2005' 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][0][:value].should == '192.0.2.2.invalid'
response[:results][1][:result_code].should == '2005' 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' response[:results][1][:value].should == 'INVALID_IPV6'
# ensure nothing gets saved to db: # ensure nothing gets saved to db:
Domain.count.should == domain_count Domain.count.should == domain_count
@ -294,8 +305,8 @@ describe 'EPP Domain', epp: true do
xml = domain_create_xml(period_value: 365, period_unit: 'd') xml = domain_create_xml(period_value: 365, period_unit: 'd')
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:result_code].should == '1000'
response[:msg].should == 'Command completed successfully' response[:msg].should == 'Command completed successfully'
response[:result_code].should == '1000'
Domain.first.valid_to.should == Date.today + 1.year Domain.first.valid_to.should == Date.today + 1.year
end end
@ -306,7 +317,7 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:results][0][:result_code].should == '2004' 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' response[:results][0][:value].should == '367'
end end
@ -391,24 +402,25 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) 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][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][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][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][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][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' response[:results][6][:value].should == '5'
end end
@ -435,7 +447,7 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:result_code].should == '2302' 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' response[:results][0][:value].should == '700b97b591ed27ec2590d19f06f88bba700b97b591ed27ec2590d19f'
end end
@ -464,7 +476,7 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:result_code].should == '2004' 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 create_settings
end end
@ -661,8 +673,8 @@ describe 'EPP Domain', epp: true do
}) })
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:msg].should == 'Admin contacts count must be between 1-10 [admin_contacts]'
response[:result_code].should == '2004' response[:result_code].should == '2004'
response[:msg].should == 'Admin contacts count must be between 1-10'
response[:clTRID].should == 'ABC-12345' response[:clTRID].should == 'ABC-12345'
Domain.count.should == domain_count Domain.count.should == domain_count
@ -678,8 +690,8 @@ describe 'EPP Domain', epp: true do
}) })
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:result_code].should == '2306'
response[:msg].should == 'Admin contact can be only citizen' response[:msg].should == 'Admin contact can be only citizen'
response[:result_code].should == '2306'
end end
end end
@ -853,7 +865,8 @@ describe 'EPP Domain', epp: true do
login_as :registrar2 do login_as :registrar2 do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:result_code].should == '2003' 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
end end
@ -970,7 +983,7 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:result_code].should == '2201' response[:result_code].should == '2201'
response[:msg].should == 'Authorization error' response[:msg].should == 'Authorization error [auth_info]'
end end
it 'ignores transfer when owner registrar requests transfer' do it 'ignores transfer when owner registrar requests transfer' do
@ -1017,7 +1030,7 @@ describe 'EPP Domain', epp: true do
epp_plain_request(xml, :xml) # transfer domain epp_plain_request(xml, :xml) # transfer domain
response = epp_plain_request(xml, :xml) # attempt second transfer response = epp_plain_request(xml, :xml) # attempt second transfer
response[:result_code].should == '2201' response[:result_code].should == '2201'
response[:msg].should == 'Authorization error' response[:msg].should == 'Authorization error [auth_info]'
end end
end end
@ -1120,27 +1133,27 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:results][0][:result_code].should == '2302' 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][0][:value].should == 'ns1.example.com'
response[:results][1][:result_code].should == '2302' 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][1][:value].should == 'ns2.example.com'
response[:results][2][:result_code].should == '2302' 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][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][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][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][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' response[:results][6][:value].should == '841936717ae427ace63c28d04918569a841936717ae427ace63c28d0'
d.domain_statuses.count.should == 2 d.domain_statuses.count.should == 2
@ -1292,11 +1305,11 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:results][0][:result_code].should == '2302' 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][0][:value].should == n.hostname
response[:results][1][:result_code].should == '2302' 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 response[:results][1][:value].should == c.code
end end
@ -1309,7 +1322,8 @@ describe 'EPP Domain', epp: true do
} }
response = epp_plain_request(domain_update_xml(xml_params), :xml) 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' response[:results][0][:result_code].should == '2003'
end end
@ -1366,7 +1380,7 @@ describe 'EPP Domain', epp: true do
response = epp_plain_request(xml, :xml) response = epp_plain_request(xml, :xml)
response[:results][0][:result_code].should == '2004' 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' response[:results][0][:value].should == '4'
end end
@ -1518,7 +1532,8 @@ describe 'EPP Domain', epp: true do
it 'does not delete domain without legal document' do it 'does not delete domain without legal document' do
response = epp_plain_request(@epp_xml.domain.delete(name: { value: 'example.ee' }), :xml) response = epp_plain_request(@epp_xml.domain.delete(name: { value: 'example.ee' }), :xml)
response[:result_code].should == '2003' 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
### CHECK ### ### CHECK ###

View file

@ -64,7 +64,7 @@ describe 'EPP Keyrelay', epp: true do
}) })
response = epp_plain_request(xml, :xml) 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 @registrar2.messages.queued.count.should == msg_count
end end

View file

@ -35,6 +35,7 @@ describe 'EPP Session', epp: true do
inactive = @epp_xml.session.login(clID: { value: 'inactive-user' }, pw: { value: 'ghyt9e4fu' }) inactive = @epp_xml.session.login(clID: { value: 'inactive-user' }, pw: { value: 'ghyt9e4fu' })
response = epp_plain_request(inactive, :xml) response = epp_plain_request(inactive, :xml)
response[:msg].should == 'Authentication error; server closing connection'
response[:result_code].should == '2501' response[:result_code].should == '2501'
end end

View file

@ -0,0 +1,33 @@
# default fabricator should be reusable
Fabricator(:certificate) do
api_user
csr "-----BEGIN CERTIFICATE REQUEST-----\n" \
"MIIE+DCCAuACAQAwgZ0xCzAJBgNVBAYTAkVFMREwDwYDVQQIDAhIYXJqdW1hYTEQ\n" \
"MA4GA1UEBwwHVGFsbGlubjEbMBkGA1UECgwSRWVzdGkgSW50ZXJuZXRpIFNBMRIw\n" \
"EAYDVQQLDAlSRUdJU1RSQVIxEjAQBgNVBAMMCXdlYmNsaWVudDEkMCIGCSqGSIb3\n" \
"DQEJARYVd2ViY2xpZW50QGludGVybmV0LmVlMIICIjANBgkqhkiG9w0BAQEFAAOC\n" \
"Ag8AMIICCgKCAgEAuXronFj8CxPWGkyUhXf+/WirkFGb8a/My2+7GvQWYE10Nq4C\n" \
"u9wDgjU3AuLw8qzwEeE3Z5uxHXWfwnshXOF6aJNCQWUsrs0odCxw69iIwCNGKhyF\n" \
"jljtx8uSH8RRSRc8BFIUkvUpmp8m7kZTlB4FDey+XaGy4p/rImiAiwfFMIJMjdE9\n" \
"9gk0EGDbomgP6KC3Ss/iQfuOFCQWSqjFuvp3mygr193YplaPgeLM1ERIW1LVFGDK\n" \
"jy6keZ3E/Vb4O4qUPDRgTMr2KWM3Auzh2hXCymHNWn3yRn5Q4KSjJbG/P7Kz5nfZ\n" \
"kY3eVRBIBll+1Q0VV7g+1B48zzjZX2qiY3iL77MV1oL17KeOO3PAxsEtptdqNgUa\n" \
"Fpp73dwPST1ZKvq8FSgDKcdTCziSeViGhXjJRpEMr8FoeKNO7nvd1maKN9HAOy75\n" \
"eSxatj6LoQ+JFN7Ci3IbwKFI7BnIHbEr9eP7O7Qbhljz2GE9+GWUqr3zwUEgpFSI\n" \
"crAnRHQI2ALakEMsryF416zg5yr/bJp8/IzgZLaKpBVLOL88sI6r+JRdM6QXvKYx\n" \
"XhamV6bH6CrR8ZYN4okaZH6sAcy8eyBnEmc05h/KsDzTNadwadeZe73F+PltoEXH\n" \
"XgtpTpQ8XarN1uLq99WD6gWilAx3LF/xetCO86+w/MkYBmfOrXge+WLUUW8CAwEA\n" \
"AaAVMBMGCSqGSIb3DQEJBzEGDAR0ZXN0MA0GCSqGSIb3DQEBCwUAA4ICAQAkTlU3\n" \
"RcI6UMRA7As2FJSph3QurPebQFoZhnhMD+hb6+hXip8MY77YxLwo/ihB9wghaZKL\n" \
"uV0BxjdZgjDt9GhA8dtPgaCp5LvB6kQYvcEzRvitN2CpJhtz39rlF3gxuy+RtpNf\n" \
"5KbC691FivoXur1qx9I7mc4snB3DTzLiJPIZ6nQzPYcSVpPCbns30N/i/sOdHO0o\n" \
"9hP5wlhCdYrOxad993m+InpMDyDWhB1+TA9ZO7gYpg8S4kBX3Cz9OXe80Pe56ZdK\n" \
"pcgjTXnUDjNSRRGamJib2lyZ/axMbb/etwyy3X+jBDuOQropkmgrPEFJHpgNlFah\n" \
"BuW7KEASqbw5YxpTSc0nDk5uxBw3voL8fk9M1sX64tbzGAEBRZnrWGeb1mOLM/YI\n" \
"K6ocAYSBhNmWUzpHTwL7qSeP9ztQUGzoGHyRjBdan+1U2G75Kpj+TjEm/X8wmtnq\n" \
"3/qVhUYNEavcZbgR1gSE45+mS8NsD7Oq0Xdc0UKsVDbUcCGIkGG9+ERAbRznfi3W\n" \
"qhChtUxySX8T3SmX5mviwlJ5OwQVjdUF1/2voPK0oFK7zV+wZqcuORzDKdqB8XV7\n" \
"MDcQjza4EOB78OmcHDgQ7nMXuY7/UL4F+bRZosxPy43X2JId5d+/GpgV8sP9dzK8\n" \
"UGJDNEZ2YsBbPuKZS+2eNZ8g3sjjFBeadvrQ1w==\n" \
"-----END CERTIFICATE REQUEST-----"
end

View file

@ -1,12 +1,16 @@
Fabricator(:contact) do Fabricator(:contact) do
code { "sh#{Faker::Number.number(8)}" }
auth_info 'password'
name { sequence(:name) { |i| "#{Faker::Name.name}#{i}" } } name { sequence(:name) { |i| "#{Faker::Name.name}#{i}" } }
phone '+372.12345678' phone '+372.12345678'
email Faker::Internet.email email Faker::Internet.email
ident '37605030299' ident '37605030299'
code { "sh#{Faker::Number.number(8)}" } ident_type 'priv'
ident_type 'op' ident_country_code 'EE'
auth_info 'ccds4324pok'
address address
registrar { Fabricate(:registrar, name: Faker::Company.name, reg_no: Faker::Company.duns_number) } registrar { Fabricate(:registrar, name: Faker::Company.name, reg_no: Faker::Company.duns_number) }
disclosure { Fabricate(:contact_disclosure) } disclosure { Fabricate(:contact_disclosure) }
# rubocop: disable Style/SymbolProc
after_validation { |c| c.disable_generate_auth_info! }
# rubocop: enamble Style/SymbolProc
end end

View file

@ -1,5 +1,5 @@
Fabricator(:domain) do Fabricator(:domain) do
name { "#{Faker::Internet.domain_word}.ee" } name { "fabricate_name#{rand(1_000_000)}.ee" }
valid_to Date.new(2014, 8, 7) valid_to Date.new(2014, 8, 7)
period 1 period 1
period_unit 'y' period_unit 'y'

View file

@ -20,6 +20,11 @@ describe ApiUser do
it 'should not have any versions' do it 'should not have any versions' do
@api_user.versions.should == [] @api_user.versions.should == []
end end
it 'should be active by default' do
@api_user.active.should == true
end
end end
context 'with valid attributes' do context 'with valid attributes' do

View file

@ -0,0 +1,61 @@
require 'rails_helper'
describe Certificate do
it { should belong_to(:api_user) }
context 'with invalid attribute' do
before :all do
@certificate = Certificate.new
end
it 'should not be valid' do
@certificate.valid?
@certificate.errors.full_messages.should match_array([
"Csr is missing"
])
end
it 'should not have any versions' do
@certificate.versions.should == []
end
end
context 'with valid attributes' do
before :all do
@certificate = Fabricate(:certificate)
end
it 'should be valid' do
@certificate.valid?
@certificate.errors.full_messages.should match_array([])
end
it 'should be valid twice' do
@certificate = Fabricate(:certificate)
@certificate.valid?
@certificate.errors.full_messages.should match_array([])
end
it 'should sign csr', epp: true do
@certificate.status.should == 'unsigned'
@certificate.sign!
@certificate.status.should == 'signed'
@certificate.crt.should_not be_blank
end
it 'should revoke crt', epp: true do
@certificate.revoke!
@certificate.status.should == 'revoked'
end
it 'should have one version' do
with_versioning do
@certificate.versions.should == []
@certificate.csr = 'new_request'
@certificate.save
@certificate.errors.full_messages.should match_array([])
@certificate.versions.size.should == 1
end
end
end
end

View file

@ -1,91 +0,0 @@
require 'rails_helper'
describe ContactDisclosure do
it { should belong_to(:contact) }
context 'about class' do
it 'should have versioning enabled?' do
ContactDisclosure.paper_trail_enabled_for_model?.should == true
end
it 'should have custom log prexied table name for versions table' do
ContactDisclosureVersion.table_name.should == 'log_contact_disclosures'
end
end
context 'with invalid attribute' do
before :all do
@contact_disclosure = ContactDisclosure.new
end
it 'should not be valid' do
@contact_disclosure.valid?
@contact_disclosure.errors.full_messages.should match_array([
])
end
it 'should not have any versions' do
@contact_disclosure.versions.should == []
end
end
context 'with valid attributes' do
before :all do
@contact_disclosure = Fabricate(:contact_disclosure)
end
it 'should be valid' do
@contact_disclosure.valid?
@contact_disclosure.errors.full_messages.should match_array([])
end
it 'should be valid twice' do
@contact_disclosure = Fabricate(:contact_disclosure)
@contact_disclosure.valid?
@contact_disclosure.errors.full_messages.should match_array([])
end
it 'should have one version' do
with_versioning do
@contact_disclosure.versions.should == []
@contact_disclosure.name = false
@contact_disclosure.save
@contact_disclosure.errors.full_messages.should match_array([])
@contact_disclosure.versions.size.should == 1
end
end
end
end
describe '.extract_attributes' do
it 'should return empty hash for empty arguments' do
result = ContactDisclosure.extract_attributes(Nokogiri::XML::Document.new)
expect(result).to eq({})
end
it 'should return empty hash if no disclosure' do
parsed_frame = Nokogiri::XML(create_contact_xml).remove_namespaces!
result = ContactDisclosure.extract_attributes(parsed_frame)
expect(result).to eq({})
end
# TODO: remodel create contact xml to support disclosure
it 'should return disclosure has if disclosure' do
epp_xml = EppXml::Contact.new
xml = epp_xml.create(
{
disclose: { value: {
voice: { value: '' },
addr: { value: '' },
name: { value: '' },
org_name: { value: '' },
email: { value: '' },
fax: { value: '' }
}, attrs: { flag: '0' }
} })
parsed_frame = Nokogiri::XML(xml).remove_namespaces!
result = ContactDisclosure.extract_attributes(parsed_frame)
expect(result).to eq({ phone: '0', email: '0', fax: '0', address: '0', name: '0', org_name: '0' })
end
end

View file

@ -39,11 +39,11 @@ describe Contact do
end end
it 'should not have creator' do it 'should not have creator' do
@contact.cr_id.should == nil @contact.creator.should == nil
end end
it 'should not have updater' do it 'should not have updater' do
@contact.up_id.should == nil @contact.updator.should == nil
end end
it 'phone should return false' do it 'phone should return false' do
@ -52,9 +52,51 @@ describe Contact do
@contact.errors[:phone].should == ["Phone nr is invalid"] @contact.errors[:phone].should == ["Phone nr is invalid"]
end end
it 'should require country code when bic' do
@contact.ident_type = 'bic'
@contact.valid?
@contact.errors[:ident_country_code].should == ['is missing']
end
it 'should require country code when priv' do
@contact.ident_type = 'priv'
@contact.valid?
@contact.errors[:ident_country_code].should == ['is missing']
end
it 'should validate correct country code' do
@contact.ident_type = 'bic'
@contact.ident_country_code = 'EE'
@contact.valid?
@contact.errors[:ident_country_code].should == []
end
it 'should require valid country code' do
@contact.ident_type = 'bic'
@contact.ident_country_code = 'INVALID'
@contact.valid?
@contact.errors[:ident_country_code].should == ['is not following ISO_3166-1 alpha 2 format']
end
it 'should convert to alpha2 country code' do
@contact.ident_type = 'bic'
@contact.ident_country_code = 'ee'
@contact.valid?
@contact.ident_country_code.should == 'EE'
end
it 'should not have any versions' do it 'should not have any versions' do
@contact.versions.should == [] @contact.versions.should == []
end 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 end
context 'with valid attributes' do context 'with valid attributes' do
@ -87,18 +129,23 @@ describe Contact do
@contact.relations_with_domain?.should == false @contact.relations_with_domain?.should == false
end end
# it 'ico should be valid' do it 'bic should be valid' do
# @contact.ident_type = 'ico' @contact.ident_type = 'bic'
# @contact.ident = '1234' @contact.ident = '1234'
# @contact.errors.full_messages.should match_array([]) @contact.valid?
# end @contact.errors.full_messages.should match_array([])
end
# it 'ident should return false' do it 'should not accept new custom code' do
# puts @contact.ident_type old_code = @contact.code
# @contact.ident = '123abc' @contact.code = 'CID:REG1:12345'
# @contact.valid? @contact.save.should == true
# @contact.errors.full_messages.should_not == [] @contact.code.should == old_code
# end end
it 'should have static password' do
@contact.auth_info.should == 'password'
end
context 'as birthday' do context 'as birthday' do
before :all do before :all do
@ -119,7 +166,8 @@ describe Contact do
invalid.each do |date| invalid.each do |date|
@contact.ident = date @contact.ident = date
@contact.valid? @contact.valid?
@contact.errors.full_messages.should == ["Ident is invalid"] @contact.errors.full_messages.should ==
["Ident Ident not in valid birthady format, should be YYYY-MM-DD"]
end end
end end
end end
@ -151,20 +199,56 @@ describe Contact do
end end
context 'after create' do 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 = Fabricate.build(:contact, code: '123asd', auth_info: 'qwe321')
@contact.code.should == '123asd' @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.auth_info.should == 'qwe321' @contact.auth_info.should == 'qwe321'
@contact.save! @contact.save.should == true
@contact.code.should_not == '123asd'
@contact.auth_info.should_not == 'qwe321' @contact.auth_info.should_not == 'qwe321'
end 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 end
context 'after update' do context 'after update' do
before :all do before :all do
@contact.code = '123asd' @contact = Fabricate.build(:contact, code: '123asd', auth_info: 'qwe321')
@contact.auth_info = 'qwe321' @contact.save
@contact.code.should == '123asd'
@auth_info = @contact.auth_info
end end
it 'should not generate new code' do it 'should not generate new code' do
@ -174,59 +258,10 @@ describe Contact do
it 'should not generate new auth_info' do it 'should not generate new auth_info' do
@contact.update_attributes(name: 'fvrsgbqevciherot23') @contact.update_attributes(name: 'fvrsgbqevciherot23')
@contact.auth_info.should == 'qwe321' @contact.auth_info.should == @auth_info
end
end
context 'with creator' do
before :all do
# @contact.created_by = @api_user
end
# TODO: change cr_id to something else
it 'should return username of creator' do
# @contact.cr_id.should == 'gitlab'
end
end
context 'with updater' do
before :all do
# @contact.updated_by = @api_user
end
# TODO: change up_id to something else
it 'should return username of updater' do
# @contact.up_id.should == 'gitlab'
end
end end
end end
end end
end
# TODO: investigate it a bit more
# describe Contact, '#relations_with_domain?' do
# context 'with relation' do
# before :all do
# create_settings
# Fabricate(:domain)
# @contact = Fabricate(:contact)
# end
# it 'should have relation with domain' do
# @contact.relations_with_domain?.should == true
# end
# end
# end
describe Contact, '.extract_params' do
it 'returns params hash'do
ph = { id: '123123', email: 'jdoe@example.com', authInfo: { pw: 'asde' },
postalInfo: { name: 'fred', addr: { cc: 'EE' } } }
Contact.extract_attributes(ph).should == {
name: 'fred',
email: 'jdoe@example.com'
}
end end
end end

View file

@ -61,7 +61,8 @@ describe Dnskey do
d = Fabricate(:domain, name: 'emta.ee', dnskeys: [@dnskey]) d = Fabricate(:domain, name: 'emta.ee', dnskeys: [@dnskey])
dk = d.dnskeys.last dk = d.dnskeys.last
dk.public_key = 'AwEAAfB9jK8rj/FAdE3t9bYXiTLpelwlgUyxbHEtvMvhdxs+yHv0h9fE '\
pk = 'AwEAAfB9jK8rj/FAdE3t9bYXiTLpelwlgUyxbHEtvMvhdxs+yHv0h9fE '\
'710u94LPAeVmXumT6SZPsoo+ALKdmTexkcU9DGQvb2+sPfModBKM/num '\ '710u94LPAeVmXumT6SZPsoo+ALKdmTexkcU9DGQvb2+sPfModBKM/num '\
'rScUw1FBe3HwRa9SqQpgpnCjIt0kEVKHAQdLOP86YznSA9uHAg9TTJuT '\ 'rScUw1FBe3HwRa9SqQpgpnCjIt0kEVKHAQdLOP86YznSA9uHAg9TTJuT '\
'LkUtgtmwNAVFr6/mG+smE1v5NbxPccsFwVTA/T1IyaI4Z48VGCP2WNro '\ 'LkUtgtmwNAVFr6/mG+smE1v5NbxPccsFwVTA/T1IyaI4Z48VGCP2WNro '\
@ -74,9 +75,14 @@ describe Dnskey do
'DshX4yJPjza/bqo0XV4WHj1szDFHe0tLN7g1Ojwtf5FR0zyHU3FN9uUa '\ 'DshX4yJPjza/bqo0XV4WHj1szDFHe0tLN7g1Ojwtf5FR0zyHU3FN9uUa '\
'y8a+dowd/fqOQA1jXR04g2PIfFYe0VudCEpmxSV9YDoqjghHeIKUX7Jn '\ 'y8a+dowd/fqOQA1jXR04g2PIfFYe0VudCEpmxSV9YDoqjghHeIKUX7Jn '\
'KiHL5gk404S5a/Bv' 'KiHL5gk404S5a/Bv'
dk.public_key = pk
dk.save dk.save
dk.ds_digest.should == 'D7045D3C2EF7332409A132D935C8E2834A2AAB769B35BC370FA68C9445398288' dk.ds_digest.should == 'D7045D3C2EF7332409A132D935C8E2834A2AAB769B35BC370FA68C9445398288'
dk.ds_key_tag.should == '31051' dk.ds_key_tag.should == '31051'
dk.public_key.should == pk
end end
end end
end end

View file

@ -28,6 +28,10 @@ describe Registrar do
@registrar.errors[:email].should == ['is invalid'] @registrar.errors[:email].should == ['is invalid']
@registrar.errors[:billing_email].should == ['is invalid'] @registrar.errors[:billing_email].should == ['is invalid']
end end
it 'should not have valid code' do
@registrar.code.should == nil
end
end end
context 'with valid attributes' do context 'with valid attributes' do
@ -59,5 +63,26 @@ describe Registrar do
it 'should return full address' do it 'should return full address' do
@registrar.address.should == 'Street 999, Town, County, Postal' @registrar.address.should == 'Street 999, Town, County, Postal'
end 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
end end

View file

@ -112,7 +112,7 @@ module Epp
end end
def next_domain_name def next_domain_name
"example#{@uniq_no.call}.ee" "example#{rand(100000000)}.ee"
end end
### REQUEST TEMPLATES ### ### REQUEST TEMPLATES ###

View file

@ -1,87 +0,0 @@
module EppContactXmlHelper
def create_contact_xml(xml_params = {})
defaults = {
postalInfo: {
name: { value: 'John Doe' },
addr: {
street: { value: '123 Example' },
city: { value: 'Tallinn' },
cc: { value: 'EE' }
}
},
voice: { value: '+372.1234567' },
email: { value: 'test@example.example' },
ident: { value: '37605030299', attrs: { type: 'op' } }
}
xml_params = defaults.deep_merge(xml_params)
epp_xml = EppXml::Contact.new(cl_trid: 'ABC-12345')
epp_xml.create(xml_params)
end
def update_contact_xml(xml_params = {})
defaults = {
id: { value: 'asd123123er' },
authInfo: { pw: { value: 'password' } },
chg: {
postalInfo: {
name: { value: 'John Doe Edited' }
},
voice: { value: '+372.7654321' },
email: { value: 'edited@example.example' },
disclose: {
value: {
voice: { value: '' },
email: { value: '' }
}, attrs: { flag: '0' }
}
}
}
xml_params = defaults.deep_merge(xml_params)
epp_xml = EppXml::Contact.new(cl_trid: 'ABC-12345')
epp_xml.update(xml_params)
end
def delete_contact_xml(xml_params = {})
defaults = { id: { value: 'sh8012' } }
xml_params = defaults.deep_merge(xml_params)
epp_xml = EppXml::Contact.new(cl_trid: 'ABC-12345')
epp_xml.delete(xml_params)
end
def info_contact_xml(xml_params = {})
defaults = { id: { value: 'sh8012' }, authInfo: { pw: { value: 'password' } } }
xml_params = defaults.deep_merge(xml_params)
epp_xml = EppXml::Contact.new(cl_trid: 'ABC-12345')
epp_xml.info(xml_params)
end
def check_contact_xml(xml_params = {})
defaults = {
id: { value: 'ad123c3' }
}
xml_params = defaults.deep_merge(xml_params)
epp_xml = EppXml::Contact.new(cl_trid: 'ABC-12345')
epp_xml.check(xml_params)
end
def check_multiple_contacts_xml
'<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<check>
<contact:check
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
<contact:id>check-1234</contact:id>
<contact:id>check-4321</contact:id>
</contact:check>
</check>
<clTRID>ABC-12345</clTRID>
</command>
</epp>'
end
end
RSpec.configure do |c|
c.include EppContactXmlHelper
end