diff --git a/CHANGELOG.md b/CHANGELOG.md index e51465b4b..343a1601e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ * Changed and added some new smtp enviroment variables. More info at application-example.yml +13.05.2015 + +* Added new environment for EPP server: 'registrant_url' +* Added Registrant portal and apache config example + 12.05.2015 * Ruby version updated to 2.2.2 diff --git a/README.md b/README.md index 2274ea172..040cce724 100644 --- a/README.md +++ b/README.md @@ -149,8 +149,8 @@ Registrar configuration (/etc/apache2/sites-enabled/registrar.conf) is as follow # Possible values include: debug, info, notice, warn, error, crit, LogLevel info - ErrorLog /var/log/apache2/registry.error.log - CustomLog /var/log/apache2/registry.access.log combined + ErrorLog /var/log/apache2/registrar.error.log + CustomLog /var/log/apache2/registrar.access.log combined SSLEngine On SSLCertificateFile /etc/ssl/certs/your.crt @@ -163,7 +163,7 @@ Registrar configuration (/etc/apache2/sites-enabled/registrar.conf) is as follow SSLCipherSuite RC4-SHA:HIGH:!ADH - # for Apache verison 2.4 or newer + # for Apache older than version 2.4 Allow from all # for Apache verison 2.4 or newer @@ -195,6 +195,76 @@ Registrar configuration (/etc/apache2/sites-enabled/registrar.conf) is as follow ``` +Registrant configuration (/etc/apache2/sites-enabled/registrant.conf) is as follows: +``` + + ServerName your-registrant-domain + ServerAdmin your@example.com + + # Rewrite /login to /registrant/login + RewriteEngine on + RewriteCond %{REQUEST_URI} ^/login [NC] + RewriteRule ^/(.*) /registrant/$1 [PT,L,QSA] + + PassengerRoot /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini + PassengerRuby /home/registry/.rbenv/shims/ruby + PassengerEnabled on + PassengerMinInstances 10 + PassengerMaxPoolSize 10 + PassengerPoolIdleTime 0 + PassengerMaxRequests 1000 + + RailsEnv production # or staging + DocumentRoot /home/registry/registrant/current/public + + # Possible values include: debug, info, notice, warn, error, crit, + LogLevel info + ErrorLog /var/log/apache2/registrant.error.log + CustomLog /var/log/apache2/registrant.access.log combined + + SSLEngine On + SSLCertificateFile /etc/ssl/certs/your.crt + SSLCertificateKeyFile /etc/ssl/private/your.key + SSLCertificateChainFile /etc/ssl/certs/your-chain-fail.pem + SSLCACertificateFile /etc/ssl/certs/ca.pem + + SSLProtocol TLSv1 + SSLHonorCipherOrder On + SSLCipherSuite RC4-SHA:HIGH:!ADH + + + # for Apache older than version 2.4 + Allow from all + + # for Apache verison 2.4 or newer + # Require all granted + + Options -MultiViews + + + + Deny from all + + + + Allow from all + + + SSLVerifyClient none + SSLVerifyDepth 1 + SSLCACertificateFile /home/registry/registry/shared/ca/certs/ca.cert.pem + SSLCARevocationFile /home/registry/registry/shared/ca/crl/crl.pem + # Uncomment in Apache 2.4 + # SSLCARevocationCheck chain + + RequestHeader set SSL_CLIENT_S_DN_CN "%{SSL_CLIENT_S_DN_CN}s" + + SSLVerifyClient require + RequestHeader set SSL_CLIENT_S_DN_CN "%{SSL_CLIENT_S_DN_CN}s" + + +``` + For Apache, REPP goes to port 443 in production, /etc/apache2/sites-enabled/repp.conf short example: ``` diff --git a/app/assets/javascripts/registrant-manifest.coffee b/app/assets/javascripts/registrant-manifest.coffee new file mode 100644 index 000000000..50d127bc5 --- /dev/null +++ b/app/assets/javascripts/registrant-manifest.coffee @@ -0,0 +1,14 @@ +#= require jquery +#= require jquery_ujs +#= require jquery.validate +#= require jquery.validate.additional-methods +#= require turbolinks +#= require bootstrap-sprockets +#= require jquery.nested_attributes +#= require shared/jquery.validate.bootstrap +#= require jquery-ui/datepicker +#= require select2 + +#= require shared/general + +#= require registrar/application diff --git a/app/assets/stylesheets/registrant-manifest.sass b/app/assets/stylesheets/registrant-manifest.sass new file mode 100644 index 000000000..154645065 --- /dev/null +++ b/app/assets/stylesheets/registrant-manifest.sass @@ -0,0 +1,13 @@ +//= require 'shared/general-manifest' +//= require 'registrant/registrant-bootstrap' +//= require 'jquery-ui/datepicker' +//= require 'select2' +//= require 'select2-bootstrap' +@import shared/fonts +@import shared/general +@import nprogress +@import nprogress-bootstrap +@import typeaheadjs +@import selectize +@import selectize.bootstrap3 +@import registrant/registrant diff --git a/app/assets/stylesheets/registrant/registrant-bootstrap.sass b/app/assets/stylesheets/registrant/registrant-bootstrap.sass new file mode 100644 index 000000000..08f6eb984 --- /dev/null +++ b/app/assets/stylesheets/registrant/registrant-bootstrap.sass @@ -0,0 +1,19 @@ +$brand-primary: #7EA82F +$navbar-default-bg: #7EA82F +$navbar-default-brand-color: #fff +$navbar-default-link-color: #fff +$border-radius-base: 2px +$body-bg: #F8F8F8 +$container-large-desktop: 1040px +$font-family-sans-serif: 'EtelkaLightProRegular', Arial, Helvetica, sans-serif +$font-family-serif: 'EtelkaLightProBold', Georgia, "Times New Roman", Times, serif +$font-size-h1: 26px +$navbar-default-link-active-color: #333 + +@import 'bootstrap-sprockets' +@import 'bootstrap' +@import 'shared/general-bootstrap' + +// Support rails error element +.field_with_errors + @extend .has-error diff --git a/app/assets/stylesheets/registrant/registrant.sass b/app/assets/stylesheets/registrant/registrant.sass new file mode 100644 index 000000000..9f046237b --- /dev/null +++ b/app/assets/stylesheets/registrant/registrant.sass @@ -0,0 +1,34 @@ +html + position: relative + min-height: 100% + +body + padding-bottom: 130px + +body > .container + height: 100% + background: #fff + padding: 60px 30px 30px 30px + +h1, h2, h3, h4 + margin-bottom: 0px !important + +// Commented out, default 20px is needed on forms +// hr + // margin-top: 10px !important + // margin-bottom: 10px !important + +.navbar li + font-weight: bold + +.footer + position: absolute + bottom: 0 + width: 100% + height: 130px + background: image_url('bg.jpg') + color: white !important + background-size: 100% + +.semifooter + padding: 42px 0 80px 0 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 73bb1dcf7..ae462b4ba 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -12,11 +12,14 @@ class ApplicationController < ActionController::Base end rescue_from CanCan::AccessDenied do |exception| - redirect_to admin_root_path, alert: exception.message if current_user.is_a?(AdminUser) - redirect_to registrar_root_path, alert: exception.message if current_user.is_a?(ApiUser) + redirect_to current_root_url, alert: exception.message + end + + helper_method :registrant_request?, :registrar_request?, :admin_request?, :current_root_url + def registrant_request? + request.path.match(/^\/registrant/) end - helper_method :registrar_request?, :admin_request? def registrar_request? request.path.match(/^\/registrar/) end @@ -25,21 +28,28 @@ class ApplicationController < ActionController::Base request.path.match(/^\/admin/) end - def after_sign_in_path_for(_resource) - rt = session[:user_return_to].to_s.presence - login_paths = [admin_login_path, registrar_login_path, '/login'] - return rt if rt && !login_paths.include?(rt) - + def current_root_url if registrar_request? registrar_root_url + elsif registrant_request? + registrar_root_url elsif admin_request? admin_root_url end end + def after_sign_in_path_for(_resource) + rt = session[:user_return_to].to_s.presence + login_paths = [admin_login_path, registrar_login_path, '/login'] + return rt if rt && !login_paths.include?(rt) + current_root_url + end + def after_sign_out_path_for(_resource) if registrar_request? registrar_login_url + elsif registrant_request? + registrant_login_url elsif admin_request? admin_login_url end diff --git a/app/controllers/registrant/depp_controller.rb b/app/controllers/registrant/depp_controller.rb new file mode 100644 index 000000000..17379b4e8 --- /dev/null +++ b/app/controllers/registrant/depp_controller.rb @@ -0,0 +1,32 @@ +class Registrant::DeppController < RegistrantController # EPP controller + helper_method :depp_current_user + + rescue_from(Errno::ECONNRESET, Errno::ECONNREFUSED) do |_exception| + redirect_to registrant_login_url, alert: t(:no_connection_to_registry) + end + + before_action :authenticate_user + def authenticate_user + redirect_to registrant_login_url and return unless depp_current_user + end + + def depp_controller? + true + end + + def depp_current_user + return nil unless current_user + @depp_current_user ||= Depp::User.new( + tag: current_user.username, + password: current_user.password + ) + end + + def response_ok? + @data.css('result').each do |x| + success_codes = %(1000, 1001, 1300, 1301) + return false unless success_codes.include?(x['code']) + end + true + end +end diff --git a/app/controllers/registrant/domains_controller.rb b/app/controllers/registrant/domains_controller.rb new file mode 100644 index 000000000..65f3e86e6 --- /dev/null +++ b/app/controllers/registrant/domains_controller.rb @@ -0,0 +1,119 @@ +class Registrant::DomainsController < Registrant::DeppController # EPP controller + before_action :init_domain, except: :new + + def index + authorize! :view, Depp::Domain + limit, offset = pagination_details + + res = depp_current_user.repp_request('domains', { details: true, limit: limit, offset: offset }) + if res.code == '200' + @response = res.parsed_body.with_indifferent_access + @contacts = @response ? @response[:contacts] : [] + + @paginatable_array = Kaminari.paginate_array( + [], total_count: @response[:total_number_of_records] + ).page(params[:page]).per(limit) + end + flash.now[:epp_results] = [{ 'code' => res.code, 'msg' => res.message }] + end + + def info + authorize! :view, Depp::Domain + @data = @domain.info(params[:domain_name]) if params[:domain_name] + if response_ok? + render 'info' + else + flash[:alert] = t(:domain_not_found) + redirect_to registrant_domains_url and return + end + end + + def check + authorize! :view, Depp::Domain + if params[:domain_name] + @data = @domain.check(params[:domain_name]) + render 'check_index' and return unless response_ok? + else + render 'check_index' + end + end + + def new + authorize! :create, Depp::Domain + @domain_params = Depp::Domain.default_params + end + + def create + authorize! :create, Depp::Domain + @domain_params = params[:domain] + @data = @domain.create(@domain_params) + + if response_ok? + redirect_to info_registrant_domains_url(domain_name: @domain_params[:name]) + else + render 'new' + end + end + + def edit + authorize! :update, Depp::Domain + @data = @domain.info(params[:domain_name]) + @domain_params = Depp::Domain.construct_params_from_server_data(@data) + end + + def update + authorize! :update, Depp::Domain + @domain_params = params[:domain] + @data = @domain.update(@domain_params) + + if response_ok? + redirect_to info_registrant_domains_url(domain_name: @domain_params[:name]) + else + params[:domain_name] = @domain_params[:name] + render 'new' + end + end + + def delete + authorize! :delete, Depp::Domain + end + + def destroy + authorize! :delete, Depp::Domain + @data = @domain.delete(params[:domain]) + @results = @data.css('result') + if response_ok? + params[:domain_name] = nil + render 'info_index' + else + params[:domain_name] = params[:domain][:name] + render 'delete' + end + end + + def renew + authorize! :renew, Depp::Domain + if params[:domain_name] && params[:cur_exp_date] + @data = @domain.renew(params) + render 'renew_index' and return unless response_ok? + else + render 'renew_index' + end + end + + def transfer + authorize! :transfer, Depp::Domain + if params[:domain_name] + @data = @domain.transfer(params) + render 'transfer_index' and return unless response_ok? + else + render 'transfer_index' + end + end + + private + + def init_domain + @domain = Depp::Domain.new(current_user: depp_current_user) + end +end diff --git a/app/controllers/registrant/sessions_controller.rb b/app/controllers/registrant/sessions_controller.rb new file mode 100644 index 000000000..859028bb3 --- /dev/null +++ b/app/controllers/registrant/sessions_controller.rb @@ -0,0 +1,130 @@ +class Registrant::SessionsController < ::SessionsController + layout 'registrant/application' + helper_method :depp_controller? + def depp_controller? + false + end + + def login + @depp_user = Depp::User.new + end + + # rubocop:disable Metrics/PerceivedComplexity + # rubocop:disable Metrics/CyclomaticComplexity + def create + @depp_user = Depp::User.new(params[:depp_user].merge( + pki: !Rails.env.development? + ) + ) + + if @depp_user.pki && request.env['HTTP_SSL_CLIENT_S_DN_CN'].blank? + @depp_user.errors.add(:base, :webserver_missing_user_name_directive) + end + + if @depp_user.pki && request.env['HTTP_SSL_CLIENT_S_DN_CN'] == '(null)' + @depp_user.errors.add(:base, :webserver_user_name_directive_should_be_required) + end + + if @depp_user.pki && request.env['HTTP_SSL_CLIENT_S_DN_CN'] != params[:depp_user][:tag] + @depp_user.errors.add(:base, :invalid_cert) + end + + if @depp_user.errors.none? && @depp_user.valid? + @api_user = ApiUser.find_by(username: params[:depp_user][:tag]) + if @api_user.active? + sign_in @api_user + redirect_to registrant_root_url + else + @depp_user.errors.add(:base, :not_active) + render 'login' + end + else + render 'login' + end + end + # rubocop:enable Metrics/CyclomaticComplexity + # rubocop:enable Metrics/PerceivedComplexity + + def login_mid + @user = User.new + end + + def mid + phone = params[:user][:phone] + client = Digidoc::Client.new + + if Rails.env.test? && phone == "123" + @user = ApiUser.find_by(identity_code: "14212128025") + sign_in(@user, event: :authentication) + return redirect_to registrant_root_url + end + + # country_codes = {'+372' => 'EST'} + response = client.authenticate( + phone: "+372#{phone}", + message_to_display: 'Authenticating', + service_name: 'Testing' + ) + + if response.faultcode + render json: { message: response.detail.message }, status: :unauthorized + return + end + + @user = find_user_by_idc(response.user_id_code) + + if @user.persisted? + session[:user_id_code] = response.user_id_code + session[:mid_session_code] = client.session_code + render json: { message: t(:check_your_phone_for_confirmation_code) }, status: :ok + else + render json: { message: t(:no_such_user) }, status: :unauthorized + end + end + + # rubocop: disable Metrics/PerceivedComplexity + # rubocop: disable Metrics/CyclomaticComplexity + # rubocop: disable Metrics/MethodLength + def mid_status + client = Digidoc::Client.new + client.session_code = session[:mid_session_code] + auth_status = client.authentication_status + + case auth_status.status + when 'OUTSTANDING_TRANSACTION' + render json: { message: t(:check_your_phone_for_confirmation_code) }, status: :ok + when 'USER_AUTHENTICATED' + @user = find_user_by_idc(session[:user_id_code]) + sign_in @user + flash[:notice] = t(:welcome) + flash.keep(:notice) + render js: "window.location = '#{registrant_root_path}'" + when 'NOT_VALID' + render json: { message: t(:user_signature_is_invalid) }, status: :bad_request + when 'EXPIRED_TRANSACTION' + render json: { message: t(:session_timeout) }, status: :bad_request + when 'USER_CANCEL' + render json: { message: t(:user_cancelled) }, status: :bad_request + when 'MID_NOT_READY' + render json: { message: t(:mid_not_ready) }, status: :bad_request + when 'PHONE_ABSENT' + render json: { message: t(:phone_absent) }, status: :bad_request + when 'SENDING_ERROR' + render json: { message: t(:sending_error) }, status: :bad_request + when 'SIM_ERROR' + render json: { message: t(:sim_error) }, status: :bad_request + when 'INTERNAL_ERROR' + render json: { message: t(:internal_error) }, status: :bad_request + else + render json: { message: t(:internal_error) }, status: :bad_request + end + end + # rubocop: enable Metrics/PerceivedComplexity + # rubocop: enable Metrics/CyclomaticComplexity + # rubocop: enable Metrics/MethodLength + + def find_user_by_idc(idc) + return User.new unless idc + ApiUser.find_by(identity_code: idc) || User.new + end +end diff --git a/app/controllers/registrant_controller.rb b/app/controllers/registrant_controller.rb new file mode 100644 index 000000000..747634372 --- /dev/null +++ b/app/controllers/registrant_controller.rb @@ -0,0 +1,16 @@ +class RegistrantController < ApplicationController + before_action :authenticate_user! + layout 'registrant/application' + + include Registrant::ApplicationHelper + + helper_method :depp_controller? + def depp_controller? + false + end + + helper_method :head_title_sufix + def head_title_sufix + t(:registrant_head_title_sufix) + end +end diff --git a/app/helpers/registrant/application_helper.rb b/app/helpers/registrant/application_helper.rb new file mode 100644 index 000000000..c1b1de6fb --- /dev/null +++ b/app/helpers/registrant/application_helper.rb @@ -0,0 +1,13 @@ +module Registrant::ApplicationHelper + def env_style + return '' if unstable_env.nil? + "background-image: url(#{image_path("registrar/bg-#{unstable_env}.png")});" + end + + def pagination_details + params[:page] ||= 1 + limit = ENV['depp_records_on_page'] || 20 + offset = ((params[:page].to_i - 1) * limit.to_i) + [limit, offset] + end +end diff --git a/app/mailers/domain_mailer.rb b/app/mailers/domain_mailer.rb index 9335cc99b..395537d8f 100644 --- a/app/mailers/domain_mailer.rb +++ b/app/mailers/domain_mailer.rb @@ -3,8 +3,13 @@ class DomainMailer < ApplicationMailer return if Rails.env.production? ? false : !TEST_EMAILS.include?(domain.registrant_email) # turn on delivery on specific request only, thus rake tasks does not deliver anything return if domain.deliver_emails != true + if domain.registrant_verification_token.blank? + logger.warn "EMAIL DID NOT DELIVERED: registrant_verification_token is missing for #{@domain.name}" + return + end @old_registrant = Registrant.find(domain.registrant_id_was) + @verification_url = "#{ENV['registrant_url']}/etc/" @domain = domain mail(to: @old_registrant.email, diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index f9ee8c988..d6471309f 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -97,6 +97,7 @@ class Epp::Domain < Domain at[:registrant_id] = regt.id delivery_date = frame.css('registrant').attr('verified').to_s.downcase == 'yes' ? nil : Time.zone.now at[:registrant_verification_asked_at] = delivery_date + at[:registrant_verification_token] = SecureRandom.hex(42) else add_epp_error('2303', 'registrant', code, [:registrant, :not_found]) end diff --git a/app/models/registrant_user.rb b/app/models/registrant_user.rb new file mode 100644 index 000000000..ca3f9a07a --- /dev/null +++ b/app/models/registrant_user.rb @@ -0,0 +1,46 @@ +require 'open3' + +# rubocop: disable Metrics/ClassLength +class ApiUser < User + include EppErrors + def epp_code_map # rubocop:disable Metrics/MethodLength + { + '2306' => [ # Parameter policy error + [:password, :blank] + ] + } + end + + # TODO: should have max request limit per day + belongs_to :registrar + has_many :certificates + + validates :username, :password, :registrar, presence: true + validates :username, uniqueness: true + + 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 + @registrar_typeahead || registrar || nil + end + + def to_s + username + end + + def queued_messages + registrar.messages.queued + end +end +# rubocop: enable Metrics/ClassLength diff --git a/app/views/domain_mailer/registrant_updated.html.erb b/app/views/domain_mailer/registrant_updated.html.erb index b992d0fe5..72115fddb 100644 --- a/app/views/domain_mailer/registrant_updated.html.erb +++ b/app/views/domain_mailer/registrant_updated.html.erb @@ -16,7 +16,7 @@ Linn: <%= @domain.registrant_city %>
Riik: <%= @domain.registrant_country %>

Muudatuse kinnitamiseks külastage palun allolevat võrgulehekülge, kontrollige uuesti üle muudatuse andmed ning vajutage nuppu kinnitan:
-https://testrar.internet.ee/app/owpieruaofaksj298317498324rquhetoiqhepoijfqperyfq9384yuqpohewg +<%= @verification_url %>

Lugupidamisega
Eesti Interneti SA @@ -41,7 +41,7 @@ City: <%= @domain.registrant_city %>
Country: <%= @domain.registrant_country %>

To confirm the update please visit this website, once again review the data and press approve:
-https://testrar.internet.ee/app/owpieruaofaksj298317498324rquhetoiqhepoijfqperyfq9384yuqpohewg +<%= @verification_url %>

Best Regards,
Estonian Internet Foundation diff --git a/app/views/domain_mailer/registrant_updated.text.erb b/app/views/domain_mailer/registrant_updated.text.erb index c4d6d6507..9b1dfd535 100644 --- a/app/views/domain_mailer/registrant_updated.text.erb +++ b/app/views/domain_mailer/registrant_updated.text.erb @@ -16,7 +16,7 @@ Linn: <%= @domain.registrant_city %> Riik: <%= @domain.registrant_country %> Muudatuse kinnitamiseks külastage palun allolevat võrgulehekülge, kontrollige uuesti üle muudatuse andmed ning vajutage nuppu kinnitan: -https://testrar.internet.ee/app/owpieruaofaksj298317498324rquhetoiqhepoijfqperyfq9384yuqpohewg +<%= @verification_url %> Lugupidamisega Eesti Interneti SA @@ -41,7 +41,7 @@ City: <%= @domain.registrant_city %> Country: <%= @domain.registrant_country %> To confirm the update please visit this website, once again review the data and press approve: -https://testrar.internet.ee/app/owpieruaofaksj298317498324rquhetoiqhepoijfqperyfq9384yuqpohewg +<%= @verification_url %> Best Regards, Estonian Internet Foundation diff --git a/app/views/layouts/registrant/application.haml b/app/views/layouts/registrant/application.haml new file mode 100644 index 000000000..beb6e4336 --- /dev/null +++ b/app/views/layouts/registrant/application.haml @@ -0,0 +1,56 @@ +!!! 5 +%html{lang: I18n.locale.to_s} + %head + %meta{charset: "utf-8"}/ + %meta{content: "IE=edge", "http-equiv" => "X-UA-Compatible"}/ + %meta{content: "width=device-width, initial-scale=1", name: "viewport"}/ + %meta{content: "Full stack top-level domain (TLD) management.", name: "description"}/ + %meta{content: "Gitlab LTD", name: "author"}/ + - if content_for? :head_title + = yield :head_title + - else + %title= t(:registrant_head_title) + = csrf_meta_tags + = stylesheet_link_tag 'registrant-manifest', media: 'all', 'data-turbolinks-track' => true + = javascript_include_tag 'registrant-manifest', 'data-turbolinks-track' => true + = favicon_link_tag 'favicon.ico' + %body + / Fixed navbar + %nav.navbar.navbar-default.navbar-fixed-top + .container + .navbar-header + %button.navbar-toggle.collapsed{"aria-controls" => "navbar", "aria-expanded" => "false", "data-target" => "#navbar", "data-toggle" => "collapse", :type => "button"} + %span.sr-only Toggle navigation + %span.icon-bar + %span.icon-bar + %span.icon-bar + = link_to registrant_root_path, class: 'navbar-brand' do + = t(:registrant_head_title) + - if unstable_env.present? + .text-center + %small{style: 'color: #0074B3;'}= unstable_env + - if current_user + .navbar-collapse.collapse + %ul.nav.navbar-nav.public-nav + - if can? :view, Depp::Domain + - active_class = %w(registrant/domains registrant/check registrant/renew registrant/tranfer registrant/keyrelays).include?(params[:controller]) ? 'active' :nil + %li{class: active_class}= link_to t(:domains), registrant_domains_path + + %ul.nav.navbar-nav.navbar-right + - if user_signed_in? + %li= link_to t(:log_out, user: current_user), '/registrant/logout' + + .container + = render 'shared/flash' + - if depp_controller? + = render 'registrar/shared/epp_results' + = yield + + %footer.footer + .container + %row + .col-md-6 + = image_tag 'eis-logo-et.png' + .col-md-6.text-right + Version + = CURRENT_COMMIT_HASH diff --git a/app/views/registrant/domains/index.haml b/app/views/registrant/domains/index.haml new file mode 100644 index 000000000..ef09b9802 --- /dev/null +++ b/app/views/registrant/domains/index.haml @@ -0,0 +1,46 @@ +- content_for :actions do + -# = link_to(t(:new), new_registrant_domain_path, class: 'btn btn-primary') += render 'shared/title', name: t(:domains) + +.row + .col-md-12{style: 'margin-bottom: -15px;'} + = form_tag info_registrant_domains_path, class: 'form-horizontal', method: :get do + .col-md-11 + .form-group + = text_field_tag :domain_name, params[:domain_name], class: 'form-control', placeholder: t(:domain_name), autocomplete: 'off', autofocus: true + .col-md-1.text-right.text-center-xs + .form-group + %button.btn.btn-default +   + %span.glyphicon.glyphicon-search +   + +%hr + +- if @response + .table-responsive + %table.table.table-hover.table-condensed + %thead + %tr + %th{class: 'col-xs-3'}= t(:name) + %th{class: 'col-xs-6'}= t(:valid) + %th{class: 'col-xs-3'}= t(:actions) + %tbody + - @response['domains'].each do |x| + %tr + %td= link_to(x['name'], info_registrant_domains_path(domain_name: x['name'])) + %td + = Time.zone.parse(x['valid_from']).try(:to_date) + \- + = Time.zone.parse(x['valid_to']).try(:to_date) + %td + = link_to(t(:view), info_registrant_domains_path(domain_name: x['name']), + class: 'btn btn-primary btn-xs') + -# = link_to(t(:edit), edit_registrant_domains_path(domain_name: x['name']), + -# class: 'btn btn-primary btn-xs') + -# = link_to(t(:renew), renew_registrant_domains_path(domain_name: x['name']), + -# class: 'btn btn-default btn-xs') + -# = link_to(t(:delete), delete_registrant_domains_path(domain_name: x['name']), + -# class: 'btn btn-default btn-xs') + + = paginate @paginatable_array diff --git a/app/views/registrant/domains/info.haml b/app/views/registrant/domains/info.haml new file mode 100644 index 000000000..30a4060d0 --- /dev/null +++ b/app/views/registrant/domains/info.haml @@ -0,0 +1,26 @@ +- content_for :actions do + -# = link_to(t(:edit), edit_registrar_domains_path(domain_name: params[:domain_name]), + -# class: 'btn btn-default') + -# = link_to(t(:renew), renew_registrar_domains_path(domain_name: params[:domain_name]), + -# class: 'btn btn-default') + -# = link_to(t(:delete), delete_registrar_domains_path(domain_name: params[:domain_name]), + -# class: 'btn btn-default') += render 'shared/title', name: truncate(@data.css('name').text) + +.row + .col-sm-12 + - if @data.css('result').first['code'] == '1000' + .row + .col-md-12= render 'registrar/domains/partials/general' + .row + .col-md-12= render 'registrar/domains/partials/contacts' + .row + .col-md-12= render 'registrar/domains/partials/statuses' + .row + .col-md-12= render 'registrar/domains/partials/nameservers' + .row + .col-md-12= render 'registrar/domains/partials/dnskeys' + - else + .row + .col-sm-6 + %h1= t(:not_found) diff --git a/app/views/registrant/sessions/login.haml b/app/views/registrant/sessions/login.haml new file mode 100644 index 000000000..74dca112a --- /dev/null +++ b/app/views/registrant/sessions/login.haml @@ -0,0 +1,21 @@ +.row + .form-signin.col-md-6.center-block.text-center + %h2.form-signin-heading.text-center= t(:log_in) + %hr + = form_for @depp_user, url: registrant_sessions_path, html: {class: 'form-signin'} do |f| + = render 'registrar/shared/errors', object: f.object + + - error_class = f.object.errors.any? ? 'has-error' : '' + %div{class: error_class} + = f.text_field :tag, class: 'form-control', placeholder: t(:username), required: true + = f.password_field :password, class: 'form-control', placeholder: t(:password), required: true + + %button.btn.btn-lg.btn-primary.btn-block{:type => 'submit'}= t(:log_in) + + %hr + = link_to '/regisrant/login/mid' do + = image_tag 'mid.gif' + -# = link_to '/registrant/login/id' do + -# = image_tag 'id_card.gif' + + diff --git a/app/views/registrant/sessions/login_mid.haml b/app/views/registrant/sessions/login_mid.haml new file mode 100644 index 000000000..ad088dafd --- /dev/null +++ b/app/views/registrant/sessions/login_mid.haml @@ -0,0 +1,40 @@ +.row + .form-signin.col-md-4.center-block.text-center + %h2.form-signin-heading.text-center= t(:log_in_with_mid) + %hr + = form_for @user, url: registrant_mid_path, auto_html5_validation: false, + html: {class: 'form-signin'} do |f| + = f.text_field :phone, class: 'form-control', + placeholder: t(:phone_no), autocomplete: 'off', required: true + %button.btn.btn-lg.btn-primary.btn-block.js-login{:type => 'submit'}= t(:log_in) + + - if ['development', 'alpha'].include?(Rails.env) + %div.text-center + 00007, 60000007, 00000766 + + :coffee + $('.js-login').attr('disabled', false) + + status_interval = null + mid_status = () -> + status_interval = setInterval((-> + $.post('/registrant/login/mid_status').fail((data) -> + clearInterval(status_interval) + flash_alert(data.responseJSON.message) + $('.js-login').attr('disabled', false) + ) + ), 1000) + + $('.js-login').on 'click', (e) -> + e.preventDefault(); + $(this).attr('disabled', true) + + $.post($('form').attr('action'), $('form').serialize()).done((data) -> + if data.message + flash_notice(data.message) + mid_status() + ).fail((data) -> + flash_alert(data.responseJSON.message) + $('.js-login').attr('disabled', false) + ) + diff --git a/config/application-example.yml b/config/application-example.yml index 38acf4f23..2c64fd4de 100644 --- a/config/application-example.yml +++ b/config/application-example.yml @@ -5,28 +5,27 @@ zonefile_export_dir: 'export/zonefiles' bank_statement_import_dir: 'import/bank_statements' legal_documents_dir: 'import/legal_documents' -# Contact epp will not accept org value by default -# and returns 2306 "Parameter value policy error" -contact_org_enabled: 'false' - # You can use `rake secret` to generate a secure secret key. # Your secret key is used for verifying the integrity of signed cookies. # If you change this key, all old signed cookies will become invalid! secret_key_base: 'please-change-it-you-can-generate-it-with-rake-secret' devise_secret: 'please-change-it-you-can-generate-it-with-rake-secret' -# Used by admin server, you can leave those empty for when running EPP server: +# Admin server configuration: 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: +# EPP server configuration webclient_ip: '127.0.0.1' webclient_cert_common_name: 'webclient' +# Contact epp will not accept org value by default +# and returns 2306 "Parameter value policy error" +contact_org_enabled: 'false' -# DEPP configuration +# DEPP server configuration (both for Registrar/Registrant servers) show_ds_data_fields: 'false' default_nameservers_count: '2' default_admin_contacts_count: '1' @@ -36,7 +35,7 @@ key_path: '/home/registry/registry/shared/ca/private/webclient.key.pem' epp_hostname: 'registry.gitlab.eu' repp_url: 'https://repp.gitlab.eu/repp/v1/' -# SMTP configuration +# SMTP configuration (for Admin/EPP/Registrar/Registrant servers) smtp_address: 'server-hostname' smtp_port: '25' # 587, 465 smtp_user_name: 'login' @@ -50,8 +49,9 @@ smtp_openssl_verify_mode: 'peer' # 'none', 'peer', 'client_once','fail_if_no_pee smtp_enable_starttls_auto: 'true' # 'false' # If your mail server requires authentication, please change. smtp_authentication: 'plain' # 'plain', 'login', 'cram_md5' +registrant_url: 'https:/registrant.example.com' # for valid email body registrant links -# autotest config overwrites +# Autotest config overwrites test: webclient_ip: '127.0.0.1' # it should match to localhost ip address crl_path: '/var/lib/jenkins/workspace/registry/ca/crl/crl.pem' diff --git a/config/application.rb b/config/application.rb index dae53708d..1fdc700f0 100644 --- a/config/application.rb +++ b/config/application.rb @@ -41,6 +41,7 @@ module Registry config.assets.precompile += %w(*.svg *.eot *.woff *.ttf) config.assets.precompile += %w(admin-manifest.css admin-manifest.js) config.assets.precompile += %w(registrar-manifest.css registrar-manifest.js) + config.assets.precompile += %w(registrant-manifest.css registrant-manifest.js) # Active Record used to suppresses errors raised within # `after_rollback`/`after_commit` callbacks and only printed them to the logs. diff --git a/config/locales/en.yml b/config/locales/en.yml index 789e71fa3..8b9963538 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -725,6 +725,8 @@ en: admin_head_title_sufix: ' - Estonian Internet Foundation' registrar_head_title: 'EIS Registrar' admin_head_title: 'Estonian Internet Foundation' + registrant_head_title: 'EIS Registrant' + registrant_head_title_sufix: ' - EIS Registrant' bind_manually: 'Bind manually' forward_invoice: 'Forward invoice' forward: 'Forward' diff --git a/config/routes.rb b/config/routes.rb index 9ac5cb152..2c784e514 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -17,6 +17,7 @@ Rails.application.routes.draw do mount Repp::API => '/' + # ADMIN ROUTES namespace :registrar do root 'polls#show' @@ -87,7 +88,63 @@ Rails.application.routes.draw do end end - # ## ADMIN ROUTES + # REGISTRANT ROUTES + namespace :registrant do + root 'domains#index' + + # resources :invoices do + # member do + # get 'download_pdf' + # match 'forward', via: [:post, :get] + # patch 'cancel' + # end + # end + + # resources :deposits + # resources :account_activities + + devise_scope :user do + get 'login' => 'sessions#login' + get 'login/mid' => 'sessions#login_mid' + post 'login/mid' => 'sessions#mid' + post 'login/mid_status' => 'sessions#mid_status' + + post 'sessions' => 'sessions#create' + post 'mid' => 'sessions#mid' + get 'logout' => '/devise/sessions#destroy' + end + + resources :domains do + resources :registrant_verifications + collection do + post 'update', as: 'update' + post 'destroy', as: 'destroy' + get 'renew' + get 'edit' + get 'info' + get 'delete' + end + end + + # resources :contacts do + # member do + # get 'delete' + # end + + # collection do + # get 'check' + # end + # end + + # resource :poll do + # collection do + # post 'confirm_keyrelay' + # post 'confirm_transfer' + # end + # end + end + + # ADMIN ROUTES namespace :admin do resources :keyrelays diff --git a/db/migrate/20150513080013_add_registrant_verification_token.rb b/db/migrate/20150513080013_add_registrant_verification_token.rb new file mode 100644 index 000000000..87d73dcdd --- /dev/null +++ b/db/migrate/20150513080013_add_registrant_verification_token.rb @@ -0,0 +1,6 @@ +class AddRegistrantVerificationToken < ActiveRecord::Migration + def change + add_column :domains, :registrant_verification_token, :string + add_index :domains, :registrant_verification_token + end +end diff --git a/db/schema.rb b/db/schema.rb index b2e3316fe..d158abd78 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150512160938) do +ActiveRecord::Schema.define(version: 20150513080013) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -301,12 +301,14 @@ ActiveRecord::Schema.define(version: 20150512160938) do t.datetime "outzone_at" t.datetime "delete_at" t.datetime "registrant_verification_asked_at" + t.string "registrant_verification_token" end add_index "domains", ["delete_at"], name: "index_domains_on_delete_at", using: :btree add_index "domains", ["outzone_at"], name: "index_domains_on_outzone_at", using: :btree add_index "domains", ["registrant_id"], name: "index_domains_on_registrant_id", using: :btree add_index "domains", ["registrant_verification_asked_at"], name: "index_domains_on_registrant_verification_asked_at", using: :btree + add_index "domains", ["registrant_verification_token"], name: "index_domains_on_registrant_verification_token", using: :btree add_index "domains", ["registrar_id"], name: "index_domains_on_registrar_id", using: :btree create_table "epp_sessions", force: :cascade do |t|