diff --git a/.rubocop.yml b/.rubocop.yml index 100e331cb..b1ceb5312 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -8,6 +8,7 @@ AllCops: - 'db/whois_schema.rb' - 'db/api_log_schema.rb' - 'db/migrate/*' + - 'db/data/*' # epp support files until 'complexity issues' will be solved - 'spec/support/epp.rb' - 'spec/support/epp_contact_xml_builder.rb' diff --git a/CHANGELOG.md b/CHANGELOG.md index 685670a92..1e0e62e39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +02.06.2015 + +* Added possibility to overwrite legal document types at application.yml level. + +01.06.2015 + +* Added separate data update, all data migration locate at db/data, more info 'rake -T data' + +29.05.2015 + +* Removed old 'iptables_counter_update_command' and added 'iptables_counter_enabled' + 26.05.2015 * Updated deploy script, now staging comes from staging branch diff --git a/Gemfile b/Gemfile index 878dc62bf..7a947bb76 100644 --- a/Gemfile +++ b/Gemfile @@ -53,6 +53,9 @@ gem 'isikukood' # for EE-id validation # deploy gem 'whenever', '~> 0.9.4', require: false +gem 'data_migrate', + github: 'gitlabeu/data_migrate', + ref: '35d22b09ff37a4e9d61ab326ad5d8eb0edf1fc81' # monitors gem 'newrelic_rpm', '~> 3.9.9.275' diff --git a/Gemfile.lock b/Gemfile.lock index 9b674285f..dbc311d2e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,6 +8,14 @@ GIT activesupport (>= 3.0, < 6.0) request_store (~> 1.1.0) +GIT + remote: git://github.com/gitlabeu/data_migrate.git + revision: 35d22b09ff37a4e9d61ab326ad5d8eb0edf1fc81 + ref: 35d22b09ff37a4e9d61ab326ad5d8eb0edf1fc81 + specs: + data_migrate (1.3.0) + rails (>= 4.1.0) + GIT remote: git://github.com/gitlabeu/epp.git revision: 505c3f2739eb1da918e54111aecfb138a822739d @@ -507,6 +515,7 @@ DEPENDENCIES coderay (~> 1.1.0) coffee-rails (~> 4.1.0) countries (~> 0.10.0) + data_migrate! database_cleaner (~> 1.3.0) deep_cloneable (~> 2.1.1) devise (~> 3.4.1) diff --git a/app/controllers/epp_controller.rb b/app/controllers/epp_controller.rb index 3a5211de5..1c8f25323 100644 --- a/app/controllers/epp_controller.rb +++ b/app/controllers/epp_controller.rb @@ -1,4 +1,5 @@ class EppController < ApplicationController + include Iptable layout false protect_from_forgery with: :null_session skip_before_action :verify_authenticity_token @@ -285,6 +286,8 @@ class EppController < ApplicationController # rubocop: enable Metrics/CyclomaticComplexity def iptables_counter_update - `ENV['iptables_counter_update_command']` if ENV['iptables_counter_update_command'].present? + return if ENV['iptables_counter_enabled'].blank? && ENV['iptables_counter_enabled'] != 'true' + return if current_user.blank? + counter_update(current_user.registrar_code, request.remote_ip) end end diff --git a/app/models/api_user.rb b/app/models/api_user.rb index e12c3b7b8..3312de5d4 100644 --- a/app/models/api_user.rb +++ b/app/models/api_user.rb @@ -11,13 +11,16 @@ class ApiUser < User } end - # TODO: should have max request limit per day + # TODO: should have max request limit per day? belongs_to :registrar has_many :certificates validates :username, :password, :registrar, :roles, presence: true validates :username, uniqueness: true + # TODO: probably cache, because it's requested on every EPP + delegate :code, to: :registrar, prefix: true + attr_accessor :registrar_typeahead ROLES = %w(super epp billing) # should not match to admin roles diff --git a/app/models/contact.rb b/app/models/contact.rb index ecb3b7f20..0fbc93d1d 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -185,7 +185,7 @@ class Contact < ActiveRecord::Base if code self.ident_country_code = code.alpha2 else - errors.add(:ident_country_code, 'is not following ISO_3166-1 alpha 2 format') + errors.add(:ident, :invalid_country_code) end end end diff --git a/app/models/depp/contact.rb b/app/models/depp/contact.rb index 3c1a62974..5233525d8 100644 --- a/app/models/depp/contact.rb +++ b/app/models/depp/contact.rb @@ -229,7 +229,12 @@ module Depp end def extension_xml - ident_xml.merge(legal_document_xml) + xml = { _anonymus: [] } + ident = ident_xml[:_anonymus].try(:first) + legal = legal_document_xml[:_anonymus].try(:first) + xml[:_anonymus] << ident if ident.present? + xml[:_anonymus] << legal if legal.present? + xml end def ident_xml diff --git a/app/models/epp/contact.rb b/app/models/epp/contact.rb index f106a4247..b07bdc124 100644 --- a/app/models/epp/contact.rb +++ b/app/models/epp/contact.rb @@ -123,7 +123,8 @@ class Epp::Contact < Contact [:email, :invalid], [:ident, :invalid], [:ident, :invalid_EE_identity_format], - [:ident, :invalid_birthday_format] + [:ident, :invalid_birthday_format], + [:ident, :invalid_country_code] ], '2302' => [ # Object exists [:code, :epp_id_taken] diff --git a/app/models/legal_document.rb b/app/models/legal_document.rb index f682e52f4..0972767f7 100644 --- a/app/models/legal_document.rb +++ b/app/models/legal_document.rb @@ -2,7 +2,11 @@ class LegalDocument < ActiveRecord::Base include Versions # version/legal_document_version.rb belongs_to :documentable, polymorphic: true - TYPES = %w(pdf bdoc ddoc zip rar gz tar 7z) + if ENV['legal_document_types'].present? + TYPES = ENV['legal_document_types'].split(',').map(&:strip) + else + TYPES = %w(pdf bdoc ddoc zip rar gz tar 7z odt doc docx) + end attr_accessor :body diff --git a/config/application-example.yml b/config/application-example.yml index 050216cee..b506ec9ba 100644 --- a/config/application-example.yml +++ b/config/application-example.yml @@ -30,8 +30,11 @@ webclient_cert_common_name: 'webclient' # and returns 2306 "Parameter value policy error" contact_org_enabled: 'false' -# Firewall countrer update command -# iptables_counter_update_command: '' +# Enable iptables counter updater +# iptables_counter_enabled: 'true' + +# Custom legal document types +# legal_document_types: "pdf,bdoc,ddoc,zip,rar,gz,tar,7z,odt,doc,docx" # DEPP server configuration (both for Registrar/Registrant servers) show_ds_data_fields: 'false' diff --git a/config/locales/en.yml b/config/locales/en.yml index 4a4707f59..4e66c4283 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -48,6 +48,7 @@ en: 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" + invalid_country_code: "Ident country code is not valid, should be in ISO_3166-1 alpha 2 format" domains: exist: 'Object association prohibits operation' diff --git a/db/migrate/20150525075550_update_certs_add_cn_from_csr.rb b/db/data/20150601083516_add_cert_common_name.rb similarity index 66% rename from db/migrate/20150525075550_update_certs_add_cn_from_csr.rb rename to db/data/20150601083516_add_cert_common_name.rb index ab56b0c8a..ef401b871 100644 --- a/db/migrate/20150525075550_update_certs_add_cn_from_csr.rb +++ b/db/data/20150601083516_add_cert_common_name.rb @@ -1,5 +1,5 @@ -class UpdateCertsAddCnFromCsr < ActiveRecord::Migration - def change +class AddCertCommonName < ActiveRecord::Migration + def self.up Certificate.all.each do |x| if x.crt.blank? && x.csr.present? pc = x.parsed_csr.try(:subject).try(:to_s) || '' @@ -9,4 +9,8 @@ class UpdateCertsAddCnFromCsr < ActiveRecord::Migration x.save end end + + def self.down + raise ActiveRecord::IrreversibleMigration + end end diff --git a/db/migrate/20150522164020_update_certs.rb b/db/data/20150601083800_add_cert_md5.rb similarity index 85% rename from db/migrate/20150522164020_update_certs.rb rename to db/data/20150601083800_add_cert_md5.rb index 5cdaa7549..5efe4e596 100644 --- a/db/migrate/20150522164020_update_certs.rb +++ b/db/data/20150601083800_add_cert_md5.rb @@ -1,5 +1,5 @@ -class UpdateCerts < ActiveRecord::Migration - def change +class AddCertMd5 < ActiveRecord::Migration + def self.up Certificate.all.each do |x| if x.crt.present? && x.csr.present? x.interface = Certificate::REGISTRAR @@ -21,4 +21,8 @@ class UpdateCerts < ActiveRecord::Migration x.save end end + + def self.down + raise ActiveRecord::IrreversibleMigration + end end diff --git a/doc/debian_build_doc.md b/doc/debian_build_doc.md index c2d40f56c..27792b2ce 100644 --- a/doc/debian_build_doc.md +++ b/doc/debian_build_doc.md @@ -42,8 +42,7 @@ Please install following lib, otherwise your bundler install might not be succes ### Firewall rate limit config -First increase the maximum possible value for the hitcount parameter -from its default value of 20 by setting the option +First increase the maximum possible value form 20 to 100 of the hitcount parameter. ip_pkt_list_tot of the xt_recent kernel module. This can be done by creating an ip_pkt_list_tot.conf file in /etc/modeprobe.d/ which contains: @@ -53,7 +52,6 @@ options xt_recent ip_pkt_list_tot=100 Once the file is created, reload the xt_recent kernel module via modprobe -r xt_recent && modprobe xt_recent or reboot the system. - #### Registrar, REPP, Restful-whois ```` @@ -70,22 +68,6 @@ $IPT -A INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --set $IPT -A INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --rcheck --seconds ${SECONDS} --hitcount ${BLOCKCOUNT} -j ${DACTION} ```` -#### EPP - -```` -#!/bin/bash -# Inspired and credits to Vivek Gite: http://www.cyberciti.biz/faq/iptables-connection-limits-howto/ -IPT=/sbin/iptables -# Max connection in seconds -SECONDS=60 -# Max connections per IP -BLOCKCOUNT=100 -# default action can be DROP or REJECT or something else. -DACTION="REJECT" -$IPT -A INPUT -p tcp --dport 700 -i eth0 -m state --state NEW -m recent --set -$IPT -A INPUT -p tcp --dport 700 -i eth0 -m state --state NEW -m recent --rcheck --seconds ${SECONDS} --hitcount ${BLOCKCOUNT} -j ${DACTION} -```` - #### Whois ```` @@ -102,3 +84,30 @@ $IPT -A INPUT -p tcp --dport 43 -i eth0 -m state --state NEW -m recent --set $IPT -A INPUT -p tcp --dport 43 -i eth0 -m state --state NEW -m recent --rcheck --seconds ${SECONDS} --hitcount ${BLOCKCOUNT} -j ${DACTION} ```` +#### EPP + +Iptables hitcounter is updated by application. + +```` +#!/bin/bash +# Inspired and credits to Vivek Gite: http://www.cyberciti.biz/faq/iptables-connection-limits-howto/ +IPT=/sbin/iptables +# Registrar handler +REGISTRAR_CODE="test" +# Max connection in seconds +SECONDS=60 +# Max connections per IP +BLOCKCOUNT=100 +# default action can be DROP or REJECT or something else. +DACTION="REJECT" +$IPT -A INPUT -p tcp --dport 700 -i eth0 -m state --state NEW -m recent --set +$IPT -A INPUT -p tcp --dport 700 -m recent --name $REGISTRAR_CODE --rdest --rcheck --hitcount ${BLOCKCOUNT} --seconds ${SECONDS} -j ${DACTION} +```` + +After adding iptable counters, please add correct permissions to proc files at path /proc/net/xt_recent + +Example command: + +```` +sudo chown registry /proc/net/xt_recent/* +```` diff --git a/lib/iptable.rb b/lib/iptable.rb new file mode 100644 index 000000000..c41bc37f4 --- /dev/null +++ b/lib/iptable.rb @@ -0,0 +1,17 @@ +module Iptable + def counter_update(registrar_code, ip) + counter_proc = "/proc/net/xt_recent/#{registrar_code}" + + begin + File.open(counter_proc, 'a') do |f| + f.puts "+#{ip}" + end + rescue Errno::ENOENT => e + logger.error "IPTABLES COUNTER UPDATE: cannot open #{counter_proc}: #{e}" + rescue Errno::EACCES => e + logger.error "IPTABLES COUNTER UPDATE: no permission #{counter_proc}: #{e}" + rescue IOError => e + logger.error "IPTABLES COUNTER UPDATE: cannot write #{ip} to #{counter_proc}: #{e}" + end + end +end diff --git a/public/assets/admin-manifest-6e6fcf039a6b92e085d41d339fec5884.js b/public/assets/admin-manifest-6e6fcf039a6b92e085d41d339fec5884.js new file mode 100644 index 000000000..a4eadcf6d --- /dev/null +++ b/public/assets/admin-manifest-6e6fcf039a6b92e085d41d339fec5884.js @@ -0,0 +1,10 @@ +!function(t,e){"object"==typeof module&&"object"==typeof module.exports?module.exports=t.document?e(t,!0):function(t){if(!t.document)throw new Error("jQuery requires a window with a document");return e(t)}:e(t)}("undefined"!=typeof window?window:this,function(t,e){function n(t){var e=t.length,n=re.type(t);return"function"===n||re.isWindow(t)?!1:1===t.nodeType&&e?!0:"array"===n||0===e||"number"==typeof e&&e>0&&e-1 in t}function i(t,e,n){if(re.isFunction(e))return re.grep(t,function(t,i){return!!e.call(t,i,t)!==n});if(e.nodeType)return re.grep(t,function(t){return t===e!==n});if("string"==typeof e){if(he.test(e))return re.filter(e,t,n);e=re.filter(e,t)}return re.grep(t,function(t){return re.inArray(t,e)>=0!==n})}function r(t,e){do t=t[e];while(t&&1!==t.nodeType);return t}function o(t){var e=we[t]={};return re.each(t.match(be)||[],function(t,n){e[n]=!0}),e}function a(){fe.addEventListener?(fe.removeEventListener("DOMContentLoaded",s,!1),t.removeEventListener("load",s,!1)):(fe.detachEvent("onreadystatechange",s),t.detachEvent("onload",s))}function s(){(fe.addEventListener||"load"===event.type||"complete"===fe.readyState)&&(a(),re.ready())}function l(t,e,n){if(void 0===n&&1===t.nodeType){var i="data-"+e.replace(De,"-$1").toLowerCase();if(n=t.getAttribute(i),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:_e.test(n)?re.parseJSON(n):n}catch(r){}re.data(t,e,n)}else n=void 0}return n}function u(t){var e;for(e in t)if(("data"!==e||!re.isEmptyObject(t[e]))&&"toJSON"!==e)return!1;return!0}function c(t,e,n,i){if(re.acceptData(t)){var r,o,a=re.expando,s=t.nodeType,l=s?re.cache:t,u=s?t[a]:t[a]&&a;if(u&&l[u]&&(i||l[u].data)||void 0!==n||"string"!=typeof e)return u||(u=s?t[a]=V.pop()||re.guid++:a),l[u]||(l[u]=s?{}:{toJSON:re.noop}),("object"==typeof e||"function"==typeof e)&&(i?l[u]=re.extend(l[u],e):l[u].data=re.extend(l[u].data,e)),o=l[u],i||(o.data||(o.data={}),o=o.data),void 0!==n&&(o[re.camelCase(e)]=n),"string"==typeof e?(r=o[e],null==r&&(r=o[re.camelCase(e)])):r=o,r}}function d(t,e,n){if(re.acceptData(t)){var i,r,o=t.nodeType,a=o?re.cache:t,s=o?t[re.expando]:re.expando;if(a[s]){if(e&&(i=n?a[s]:a[s].data)){re.isArray(e)?e=e.concat(re.map(e,re.camelCase)):e in i?e=[e]:(e=re.camelCase(e),e=e in i?[e]:e.split(" ")),r=e.length;for(;r--;)delete i[e[r]];if(n?!u(i):!re.isEmptyObject(i))return}(n||(delete a[s].data,u(a[s])))&&(o?re.cleanData([t],!0):ne.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}function h(){return!0}function p(){return!1}function f(){try{return fe.activeElement}catch(t){}}function g(t){var e=Le.split("|"),n=t.createDocumentFragment();if(n.createElement)for(;e.length;)n.createElement(e.pop());return n}function m(t,e){var n,i,r=0,o=typeof t.getElementsByTagName!==Ce?t.getElementsByTagName(e||"*"):typeof t.querySelectorAll!==Ce?t.querySelectorAll(e||"*"):void 0;if(!o)for(o=[],n=t.childNodes||t;null!=(i=n[r]);r++)!e||re.nodeName(i,e)?o.push(i):re.merge(o,m(i,e));return void 0===e||e&&re.nodeName(t,e)?re.merge([t],o):o}function v(t){Ee.test(t.type)&&(t.defaultChecked=t.checked)}function y(t,e){return re.nodeName(t,"table")&&re.nodeName(11!==e.nodeType?e:e.firstChild,"tr")?t.getElementsByTagName("tbody")[0]||t.appendChild(t.ownerDocument.createElement("tbody")):t}function b(t){return t.type=(null!==re.find.attr(t,"type"))+"/"+t.type,t}function w(t){var e=Ye.exec(t.type);return e?t.type=e[1]:t.removeAttribute("type"),t}function x(t,e){for(var n,i=0;null!=(n=t[i]);i++)re._data(n,"globalEval",!e||re._data(e[i],"globalEval"))}function k(t,e){if(1===e.nodeType&&re.hasData(t)){var n,i,r,o=re._data(t),a=re._data(e,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(i=0,r=s[n].length;r>i;i++)re.event.add(e,n,s[n][i])}a.data&&(a.data=re.extend({},a.data))}}function C(t,e){var n,i,r;if(1===e.nodeType){if(n=e.nodeName.toLowerCase(),!ne.noCloneEvent&&e[re.expando]){r=re._data(e);for(i in r.events)re.removeEvent(e,i,r.handle);e.removeAttribute(re.expando)}"script"===n&&e.text!==t.text?(b(e).text=t.text,w(e)):"object"===n?(e.parentNode&&(e.outerHTML=t.outerHTML),ne.html5Clone&&t.innerHTML&&!re.trim(e.innerHTML)&&(e.innerHTML=t.innerHTML)):"input"===n&&Ee.test(t.type)?(e.defaultChecked=e.checked=t.checked,e.value!==t.value&&(e.value=t.value)):"option"===n?e.defaultSelected=e.selected=t.defaultSelected:("input"===n||"textarea"===n)&&(e.defaultValue=t.defaultValue)}}function _(e,n){var i,r=re(n.createElement(e)).appendTo(n.body),o=t.getDefaultComputedStyle&&(i=t.getDefaultComputedStyle(r[0]))?i.display:re.css(r[0],"display");return r.detach(),o}function D(t){var e=fe,n=Je[t];return n||(n=_(t,e),"none"!==n&&n||(Ge=(Ge||re("