diff --git a/Gemfile b/Gemfile index 976c4e2cd..db9d4e366 100644 --- a/Gemfile +++ b/Gemfile @@ -78,6 +78,9 @@ gem 'daemons' # cron gem 'whenever', '~> 0.9.4', require: false +# for dates and times +gem 'iso8601', '~> 0.8.2' + group :development, :test do # for inserting dummy data gem 'activerecord-import', '~> 0.6.0' diff --git a/Gemfile.lock b/Gemfile.lock index 53f75e730..2669b642f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -151,6 +151,7 @@ GEM i18n (0.6.11) ice_nine (0.11.0) isikukood (0.1.2) + iso8601 (0.8.2) jbuilder (2.2.2) activesupport (>= 3.0.0, < 5) multi_json (~> 1.2) @@ -395,6 +396,7 @@ DEPENDENCIES guard-rubocop (~> 1.1.0) haml-rails (~> 0.5.3) isikukood + iso8601 (~> 0.8.2) jbuilder (~> 2.0) jquery-rails kaminari (~> 0.16.1) diff --git a/app/models/epp/epp_domain.rb b/app/models/epp/epp_domain.rb index 89317989a..8044b46ca 100644 --- a/app/models/epp/epp_domain.rb +++ b/app/models/epp/epp_domain.rb @@ -357,7 +357,7 @@ class Epp::EppDomain < Domain end abs_datetime = parsed_frame.css('absolute').text - abs_datetime = abs_datetime.to_date if abs_datetime + abs_datetime = DateTime.parse(abs_datetime) if abs_datetime.present? transaction do kr = keyrelays.create( @@ -373,14 +373,16 @@ class Epp::EppDomain < Domain accepter: registrar ) - registrar.messages.create( + return false unless valid? + + registrar.messages.create!( body: 'Key Relay action completed successfully.', attached_obj_type: kr.class.to_s, attached_obj_id: kr.id ) - - kr end + + true end ### VALIDATIONS ### diff --git a/app/models/keyrelay.rb b/app/models/keyrelay.rb index 5beb8b77f..0b5483bba 100644 --- a/app/models/keyrelay.rb +++ b/app/models/keyrelay.rb @@ -1,8 +1,34 @@ class Keyrelay < ActiveRecord::Base + include EppErrors + belongs_to :domain belongs_to :requester, class_name: 'Registrar' belongs_to :accepter, class_name: 'Registrar' delegate :name, to: :domain, prefix: true + + validates :expiry_relative, duration_iso8601: true + + def epp_code_map + { + '2005' => [ + [:expiry_relative, :unknown_pattern, { value: { obj: 'relative', val: expiry_relative } }] + ] + } + end + + def status + if expiry_relative + exp_date = pa_date + ISO8601::Duration.new(expiry_relative).to_seconds + elsif expiry_absolute + exp_date = expiry_positive + end + + if Time.now > exp_date + return 'expired' + else + return 'pending' + end + end end diff --git a/app/models/message.rb b/app/models/message.rb index 9813479e4..831ff970a 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -5,6 +5,8 @@ class Message < ActiveRecord::Base scope :queued, -> { where(queued: true) } + validates :body, presence: true + def dequeue self.queued = false save diff --git a/app/validators/duration_iso8601_validator.rb b/app/validators/duration_iso8601_validator.rb new file mode 100644 index 000000000..ceffb92ee --- /dev/null +++ b/app/validators/duration_iso8601_validator.rb @@ -0,0 +1,9 @@ +class DurationIso8601Validator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + return unless value.present? + + ISO8601::Duration.new(value) + rescue => _e + record.errors[attribute] << (options[:message] || record.errors.generate_message(attribute, :unknown_pattern)) + end +end diff --git a/config/locales/en.yml b/config/locales/en.yml index eacded2fc..8efe42170 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -204,6 +204,11 @@ en: taken: 'Public key already exists' blank: 'Public key is missing' + keyrelay: + attributes: + expiry_relative: + unknown_pattern: 'Expiry relative must be compatible to ISO 8601' + attributes: epp_domain: &epp_domain_attributes name: 'Domain name' diff --git a/spec/epp/keyrelay_spec.rb b/spec/epp/keyrelay_spec.rb index 3349c7195..b5ef19712 100644 --- a/spec/epp/keyrelay_spec.rb +++ b/spec/epp/keyrelay_spec.rb @@ -40,5 +40,29 @@ describe 'EPP Keyrelay', epp: true do expect(zone.messages.queued.count).to eq(1) end + + it 'returns an error on invalid relative expiry' do + xml = epp_xml.keyrelay({ + name: { value: 'example.ee' }, + keyData: { + flags: { value: '256' }, + protocol: { value: '3' }, + alg: { value: '8' }, + pubKey: { value: 'cmlraXN0aGViZXN0' } + }, + authInfo: { + pw: { value: domain.auth_info } + }, + expiry: { + relative: { value: 'Invalid Expiry' } + } + }) + + response = epp_request(xml, :xml, :elkdata) + expect(response[:msg]).to eq('Expiry relative must be compatible to ISO 8601') + expect(response[:results][0][:value]).to eq('Invalid Expiry') + + expect(zone.messages.queued.count).to eq(0) + end end end diff --git a/spec/fabricators/keyrelay_fabricator.rb b/spec/fabricators/keyrelay_fabricator.rb new file mode 100644 index 000000000..451a967de --- /dev/null +++ b/spec/fabricators/keyrelay_fabricator.rb @@ -0,0 +1,4 @@ +Fabricator(:keyrelay) do + pa_date { DateTime.now } + expiry_relative 'P1W' +end diff --git a/spec/models/keyrelay_spec.rb b/spec/models/keyrelay_spec.rb new file mode 100644 index 000000000..918d4cc08 --- /dev/null +++ b/spec/models/keyrelay_spec.rb @@ -0,0 +1,23 @@ +require 'rails_helper' + +describe Keyrelay do + it { should belong_to(:domain) } + it { should belong_to(:requester) } + it { should belong_to(:accepter) } + + it 'is in pending status' do + kr = Fabricate(:keyrelay) + expect(kr.status).to eq('pending') + end + + it 'is in expired status' do + kr = Fabricate(:keyrelay, pa_date: DateTime.now - 2.weeks) + expect(kr.status).to eq('expired') + end + + it 'does not accept invalid relative expiry' do + kr = Fabricate.build(:keyrelay, expiry_relative: 'adf') + expect(kr.save).to eq(false) + expect(kr.errors[:expiry_relative].first).to eq('Expiry relative must be compatible to ISO 8601') + end +end