diff --git a/Gemfile b/Gemfile index ad31862..733acd4 100644 --- a/Gemfile +++ b/Gemfile @@ -1,58 +1,60 @@ source 'https://rubygems.org' group :development, :test do gem 'pry-byebug' end group :development do gem 'rubocop', '0.35', require: false gem 'yard' gem 'yard-tomdoc' gem 'guard-yard' gem 'guard-minitest', require: false gem 'guard', require: false gem 'capistrano', '3.2.1', require: false # pkg:capistrano end group :production do gem 'unicorn' # pkg:unicorn end group :assets do gem 'coffee-rails', '4.0.1' # pkg: ryby-coffee-rails end # Lock jessie versions # gem 'rails', '4.1.8' # pkg:rails gem 'i18n', '0.6.9' gem 'json', '1.8.1' gem 'mail', '2.6.1' gem 'mime-types', '1.25' gem 'minitest', '5.4.2' gem 'rack', '1.5.2' gem 'rack-test', '0.6.2' gem 'rake', '10.3.2' gem 'sprockets', '2.12.3' gem 'sprockets-rails', '2.1.3' gem 'thread_safe', '0.3.3' gem 'tzinfo', '1.1.0' gem 'mysql2', '0.3.16' # pkg:ruby-mysql2 gem 'jquery-rails', '3.1.2' # pkg:ruby-jquery-rails gem 'state_machine', '1.2.0' # pkg: ruby-state-machine +gem 'nokogiri', '1.6.3' + # Worker gem 'faraday', '0.9.0' # Devise & dependencies gem 'devise', '3.5.2' # pkg:ruby-devise gem 'warden', '1.2.3' gem 'bcrypt', '3.1.7' gem 'orm_adapter', '0.5.0' gem 'responders', '1.1.2' group :test do gem 'factory_girl_rails', '4.4.1' end diff --git a/Gemfile.lock b/Gemfile.lock index d6098ba..bda08f8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,225 +1,229 @@ GEM remote: https://rubygems.org/ specs: actionmailer (4.1.8) actionpack (= 4.1.8) actionview (= 4.1.8) mail (~> 2.5, >= 2.5.4) actionpack (4.1.8) actionview (= 4.1.8) activesupport (= 4.1.8) rack (~> 1.5.2) rack-test (~> 0.6.2) actionview (4.1.8) activesupport (= 4.1.8) builder (~> 3.1) erubis (~> 2.7.0) activemodel (4.1.8) activesupport (= 4.1.8) builder (~> 3.1) activerecord (4.1.8) activemodel (= 4.1.8) activesupport (= 4.1.8) arel (~> 5.0.0) activesupport (4.1.8) i18n (~> 0.6, >= 0.6.9) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) thread_safe (~> 0.1) tzinfo (~> 1.1) arel (5.0.1.20140414130214) ast (2.1.0) astrolabe (1.3.1) parser (~> 2.2) bcrypt (3.1.7) builder (3.2.2) byebug (4.0.5) columnize (= 0.9.0) capistrano (3.2.1) i18n rake (>= 10.0.0) sshkit (~> 1.3) coderay (1.1.0) coffee-rails (4.0.1) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.0) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.9.1.1) colorize (0.7.7) columnize (0.9.0) devise (3.5.2) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 3.2.6, < 5) responders thread_safe (~> 0.1) warden (~> 1.2.3) erubis (2.7.0) execjs (2.6.0) factory_girl (4.4.0) activesupport (>= 3.0.0) factory_girl_rails (4.4.1) factory_girl (~> 4.4.0) railties (>= 3.0.0) faraday (0.9.0) multipart-post (>= 1.2, < 3) ffi (1.9.10) formatador (0.2.5) guard (2.13.0) formatador (>= 0.2.4) listen (>= 2.7, <= 4.0) lumberjack (~> 1.0) nenv (~> 0.1) notiffany (~> 0.0) pry (>= 0.9.12) shellany (~> 0.0) thor (>= 0.18.1) guard-compat (1.2.1) guard-minitest (2.4.4) guard-compat (~> 1.2) minitest (>= 3.0) guard-yard (2.1.4) guard (>= 1.1.0) yard (>= 0.7.0) hike (1.2.3) i18n (0.6.9) jquery-rails (3.1.2) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) json (1.8.1) kgio (2.9.3) listen (3.0.3) rb-fsevent (>= 0.9.3) rb-inotify (>= 0.9) lumberjack (1.0.9) mail (2.6.1) mime-types (>= 1.16, < 3) method_source (0.8.2) mime-types (1.25) + mini_portile (0.6.0) minitest (5.4.2) multi_json (1.11.2) multipart-post (2.0.0) mysql2 (0.3.16) nenv (0.2.0) net-scp (1.2.1) net-ssh (>= 2.6.5) net-ssh (2.9.2) + nokogiri (1.6.3) + mini_portile (= 0.6.0) notiffany (0.0.8) nenv (~> 0.1) shellany (~> 0.0) orm_adapter (0.5.0) parser (2.2.3.0) ast (>= 1.1, < 3.0) powerpack (0.1.1) pry (0.10.1) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) pry-byebug (3.1.0) byebug (~> 4.0) pry (~> 0.10) rack (1.5.2) rack-test (0.6.2) rack (>= 1.0) rails (4.1.8) actionmailer (= 4.1.8) actionpack (= 4.1.8) actionview (= 4.1.8) activemodel (= 4.1.8) activerecord (= 4.1.8) activesupport (= 4.1.8) bundler (>= 1.3.0, < 2.0) railties (= 4.1.8) sprockets-rails (~> 2.0) railties (4.1.8) actionpack (= 4.1.8) activesupport (= 4.1.8) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (2.0.0) raindrops (0.15.0) rake (10.3.2) rb-fsevent (0.9.6) rb-inotify (0.9.5) ffi (>= 0.5.0) responders (1.1.2) railties (>= 3.2, < 4.2) rubocop (0.35.0) astrolabe (~> 1.3) parser (>= 2.2.3.0, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) ruby-progressbar (~> 1.7) ruby-progressbar (1.7.5) shellany (0.0.1) slop (3.6.0) sprockets (2.12.3) hike (~> 1.2) multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) sprockets-rails (2.1.3) actionpack (>= 3.0) activesupport (>= 3.0) sprockets (~> 2.8) sshkit (1.7.1) colorize (>= 0.7.0) net-scp (>= 1.1.2) net-ssh (>= 2.8.0) state_machine (1.2.0) thor (0.19.1) thread_safe (0.3.3) tilt (1.4.1) tomparse (0.4.2) tzinfo (1.1.0) thread_safe (~> 0.1) unicorn (4.9.0) kgio (~> 2.6) rack raindrops (~> 0.7) warden (1.2.3) rack (>= 1.0) yard (0.8.7.6) yard-tomdoc (0.7.1) tomparse (>= 0.4.0) yard PLATFORMS ruby DEPENDENCIES bcrypt (= 3.1.7) capistrano (= 3.2.1) coffee-rails (= 4.0.1) devise (= 3.5.2) factory_girl_rails (= 4.4.1) faraday (= 0.9.0) guard guard-minitest guard-yard i18n (= 0.6.9) jquery-rails (= 3.1.2) json (= 1.8.1) mail (= 2.6.1) mime-types (= 1.25) minitest (= 5.4.2) mysql2 (= 0.3.16) + nokogiri (= 1.6.3) orm_adapter (= 0.5.0) pry-byebug rack (= 1.5.2) rack-test (= 0.6.2) rails (= 4.1.8) rake (= 10.3.2) responders (= 1.1.2) rubocop (= 0.35) sprockets (= 2.12.3) sprockets-rails (= 2.1.3) state_machine (= 1.2.0) thread_safe (= 0.3.3) tzinfo (= 1.1.0) unicorn warden (= 1.2.3) yard yard-tomdoc diff --git a/app/helpers/domains_helper.rb b/app/helpers/domains_helper.rb index 7c69184..992400f 100644 --- a/app/helpers/domains_helper.rb +++ b/app/helpers/domains_helper.rb @@ -1,30 +1,38 @@ module DomainsHelper # Human names for domain states def human_state(state) human = case state.to_sym when :initial then 'Initial' when :pending_install then 'Becoming public' when :pending_signing then 'Signing zone' when :wait_for_ready then 'Waiting for KSK to become ready' when :pending_ds then 'Publishing DS records' when :pending_ds_rollover then 'Performing KSK rollover' when :pending_plain then 'Removing dnssec' when :pending_remove then 'Preparing removal' when :operational then 'Operational' when :destroy then 'Ready to be destroyed' else state end prog = Domain.dnssec_progress(state) return human if prog.nil? "#{human} (#{prog})" end # Most of the time the parent zone will be easily computed def guess_parent_zone(name) name.split('.', 2).last || '' end + + def dnssec_policy_human(policy) + info = policy.info.map { |name, value| + [name, seconds_to_human(value)].join(': ') + } + + "#{policy.name}: (#{info.join(' | ')})" + end end diff --git a/app/models/dnssec_policy.rb b/app/models/dnssec_policy.rb index a3730c1..a836ad9 100644 --- a/app/models/dnssec_policy.rb +++ b/app/models/dnssec_policy.rb @@ -1,2 +1,25 @@ class DnssecPolicy < ActiveRecord::Base + + ATTRIBUTES = { + 'KSK rollover' => { + css: 'Keys KSK Lifetime', + type: :iso8601 + }, + 'ZSK rollover' => { + css: 'Keys ZSK Lifetime', + type: :iso8601 + } + } + + def info + hash = {} + xml = Nokogiri::XML(policy) + + ATTRIBUTES.each { |name, attr| + hash[name] = xml.at_css(attr[:css]).content + hash[name] = Iso8601Duration.to_seconds(hash[name]) if attr[:type] == :iso8601 + } + + hash + end end diff --git a/app/views/domains/_dnssec_form.html.erb b/app/views/domains/_dnssec_form.html.erb index 39e1dc5..2be6a5a 100644 --- a/app/views/domains/_dnssec_form.html.erb +++ b/app/views/domains/_dnssec_form.html.erb @@ -1,22 +1,22 @@ -<%= bootstrap_form_for(@domain, layout: :horizontal, label_col: 'col-sm-2', control_col: 'col-sm-4') do |f| %> +<%= bootstrap_form_for(@domain, layout: :horizontal, label_col: 'col-sm-2', control_col: 'col-sm-6') do |f| %> <%= f.hidden_field :group_id %> <%= f.static_control :name %> <%= f.select :dnssec, [['Enable', true], ['Disable', false]] %> <% dnssec_was_or_is = @domain.dnssec_changed? ? @domain.dnssec_was : @domain.dnssec %> <% if dnssec_was_or_is %> <%= f.static_control label: 'Dnssec policy' do %> <%= @domain.dnssec_policy.try(:name) %> <% end %> <%= f.static_control :dnssec_parent_authority, label: 'Parent Authority' %> <%= f.static_control :dnssec_parent, label: 'Parent zone' %> <% else %>
> - <%= f.collection_select :dnssec_policy_id, DnssecPolicy.all, :id, :name, help: 'You will not be able to change policy once dnssec is enabled.' %> + <%= f.collection_radio_buttons :dnssec_policy_id, DnssecPolicy.all, :id, ->(policy) { dnssec_policy_human(policy) }, help: 'You will not be able to change policy once dnssec is enabled.' %> <%= f.select :dnssec_parent_authority, Domain.dnssec_parent_authorities, include_blank: true, label: 'Parent authority', help: 'WebDNS will manage DS records automatically, handling initial setup and key rollovers.' %> <%= f.text_field :dnssec_parent, value: guess_parent_zone(@domain.name), label: 'Parent zone', help: 'The parent zone to publish the DS records.' %>
<% end %> <%= f.submit 'Save', class: 'btn btn-primary col-sm-offset-2' %> <% end %> diff --git a/config/application.rb b/config/application.rb index a189c06..b79d38a 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,41 +1,42 @@ require File.expand_path('../boot', __FILE__) require 'rails/all' # Production doesn't use bundler # you've limited to :test, :development, or :production. if ENV['RAILS_ENV'] != 'production' Bundler.require(*Rails.groups) else # Dependencies to load before starting rails in production require 'devise' require 'jquery-rails' require 'coffee-rails' require 'state_machine' + require 'nokogiri' end module WebDNS class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. config.time_zone = 'Europe/Athens' # Store/Read localtime from the database config.active_record.default_timezone = :local config.active_record.schema_format = :sql # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de config.autoload_paths << Rails.root.join('lib') config.x = {} end def self.settings Application.config.x end end diff --git a/lib/iso8601_duration.rb b/lib/iso8601_duration.rb new file mode 100644 index 0000000..3e692d9 --- /dev/null +++ b/lib/iso8601_duration.rb @@ -0,0 +1,54 @@ +require 'application_helper' + +module Iso8601Duration + extend self + + TIME_PERIODS = ApplicationHelper::TIME_PERIODS.invert + def to_seconds(duration) + total = 0 + + atomize(duration).each { |k, val| + next unless secs = TIME_PERIODS[k.to_s] + total += secs.to_i * val + } + + total + end + + def atomize(input) + duration = parse(input) + + components = parse_tokens(duration) + components.delete(:time) # clean time capture + + components + end + + def parse_tokens(tokens) + components = tokens.names.zip(tokens.captures).map! do |k, v| + value = v.nil? ? v : v.tr(',', '.') + [k.to_sym, value.to_i] + end + + Hash[components] + end + + def parse(input) + input.match(/^ + (?\+|-)? + P(?: + (?: + (?:(?\d+(?:[,.]\d+)?)Y)? + (?:(?\d+(?:[.,]\d+)?)M)? + (?:(?\d+(?:[.,]\d+)?)D)? + (?