mirror of
https://github.com/internetee/registry.git
synced 2025-07-23 11:16:00 +02:00
commit
fbbada1c37
33 changed files with 712 additions and 215 deletions
|
@ -58,5 +58,6 @@ module Repp
|
|||
mount Repp::ContactV1
|
||||
mount Repp::AccountV1
|
||||
mount Repp::DomainTransfersV1
|
||||
mount Repp::NameserversV1
|
||||
end
|
||||
end
|
||||
|
|
44
app/api/repp/nameservers_v1.rb
Normal file
44
app/api/repp/nameservers_v1.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
module Repp
|
||||
class NameserversV1 < Grape::API
|
||||
version 'v1', using: :path
|
||||
|
||||
resource 'registrar/nameservers' do
|
||||
put '/' do
|
||||
params do
|
||||
requires :data, type: Hash, allow_blank: false do
|
||||
requires :type, type: String, allow_blank: false
|
||||
requires :id, type: String, allow_blank: false
|
||||
requires :attributes, type: Hash, allow_blank: false do
|
||||
requires :hostname, type: String, allow_blank: false
|
||||
requires :ipv4, type: Array
|
||||
requires :ipv6, type: Array
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
hostname = params[:data][:id]
|
||||
|
||||
unless current_user.registrar.nameservers.exists?(hostname: hostname)
|
||||
error!({ errors: [{ title: "Hostname #{hostname} does not exist" }] }, 404)
|
||||
end
|
||||
|
||||
new_attributes = {
|
||||
hostname: params[:data][:attributes][:hostname],
|
||||
ipv4: params[:data][:attributes][:ipv4],
|
||||
ipv6: params[:data][:attributes][:ipv6],
|
||||
}
|
||||
|
||||
begin
|
||||
current_user.registrar.replace_nameservers(hostname, new_attributes)
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
error!({ errors: e.record.errors.full_messages.map { |error| { title: error } } }, 400)
|
||||
end
|
||||
|
||||
status 200
|
||||
@response = { data: { type: 'nameserver',
|
||||
id: params[:data][:attributes][:hostname],
|
||||
attributes: params[:data][:attributes] } }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,59 @@
|
|||
class Registrar
|
||||
class RegistrarNameserversController < DeppController
|
||||
def edit
|
||||
authorize! :manage, :repp
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :manage, :repp
|
||||
|
||||
ipv4 = params[:ipv4].split("\r\n")
|
||||
ipv6 = params[:ipv6].split("\r\n")
|
||||
|
||||
uri = URI.parse("#{ENV['repp_url']}registrar/nameservers")
|
||||
request = Net::HTTP::Put.new(uri, 'Content-Type' => 'application/json')
|
||||
request.body = { data: { type: 'nameserver', id: params[:old_hostname],
|
||||
attributes: { hostname: params[:new_hostname],
|
||||
ipv4: ipv4,
|
||||
ipv6: ipv6 } } }.to_json
|
||||
request.basic_auth(current_user.username, current_user.password)
|
||||
|
||||
if Rails.env.test?
|
||||
response = Net::HTTP.start(uri.hostname, uri.port,
|
||||
use_ssl: (uri.scheme == 'https'),
|
||||
verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
|
||||
http.request(request)
|
||||
end
|
||||
elsif Rails.env.development?
|
||||
client_cert = File.read(ENV['cert_path'])
|
||||
client_key = File.read(ENV['key_path'])
|
||||
response = Net::HTTP.start(uri.hostname, uri.port,
|
||||
use_ssl: (uri.scheme == 'https'),
|
||||
verify_mode: OpenSSL::SSL::VERIFY_NONE,
|
||||
cert: OpenSSL::X509::Certificate.new(client_cert),
|
||||
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
|
||||
http.request(request)
|
||||
end
|
||||
else
|
||||
client_cert = File.read(ENV['cert_path'])
|
||||
client_key = File.read(ENV['key_path'])
|
||||
response = Net::HTTP.start(uri.hostname, uri.port,
|
||||
use_ssl: (uri.scheme == 'https'),
|
||||
cert: OpenSSL::X509::Certificate.new(client_cert),
|
||||
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
|
||||
http.request(request)
|
||||
end
|
||||
end
|
||||
|
||||
parsed_response = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
if response.code == '200'
|
||||
flash[:notice] = t '.replaced'
|
||||
redirect_to registrar_domains_url
|
||||
else
|
||||
@api_errors = parsed_response[:errors]
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -40,7 +40,7 @@ class Domain < ActiveRecord::Base
|
|||
has_many :contacts, through: :domain_contacts, source: :contact
|
||||
has_many :admin_contacts, through: :admin_domain_contacts, source: :contact
|
||||
has_many :tech_contacts, through: :tech_domain_contacts, source: :contact
|
||||
has_many :nameservers, dependent: :destroy
|
||||
has_many :nameservers, dependent: :destroy, inverse_of: :domain
|
||||
|
||||
accepts_nested_attributes_for :nameservers, allow_destroy: true,
|
||||
reject_if: proc { |attrs| attrs[:hostname].blank? }
|
||||
|
|
|
@ -2,18 +2,31 @@ class Nameserver < ActiveRecord::Base
|
|||
include Versions # version/nameserver_version.rb
|
||||
include EppErrors
|
||||
|
||||
# belongs_to :registrar
|
||||
belongs_to :domain
|
||||
HOSTNAME_REGEXP = /\A(([a-zA-Z0-9]|[a-zA-ZäöüõšžÄÖÜÕŠŽ0-9][a-zA-ZäöüõšžÄÖÜÕŠŽ0-9\-]
|
||||
*[a-zA-ZäöüõšžÄÖÜÕŠŽ0-9])\.)
|
||||
*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]
|
||||
*[A-Za-z0-9])\z/x
|
||||
|
||||
# scope :owned_by_registrar, -> (registrar) { joins(:domain).where('domains.registrar_id = ?', registrar.id) }
|
||||
IPV4_REGEXP = /\A(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}
|
||||
([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\z/x
|
||||
|
||||
# rubocop: disable Metrics/LineLength
|
||||
validates :hostname, format: { with: /\A(([a-zA-Z0-9]|[a-zA-ZäöüõšžÄÖÜÕŠŽ0-9][a-zA-ZäöüõšžÄÖÜÕŠŽ0-9\-]*[a-zA-ZäöüõšžÄÖÜÕŠŽ0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])\z/ }
|
||||
# validates :ipv4, format: { with: /\A(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\z/, allow_blank: true }
|
||||
# validates :ipv6, format: { with: /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/, allow_blank: true }
|
||||
validate :val_ipv4
|
||||
validate :val_ipv6
|
||||
# rubocop: enable Metrics/LineLength
|
||||
IPV6_REGEXP = /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|
|
||||
([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|
|
||||
([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|
|
||||
([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|
|
||||
([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|
|
||||
:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|
|
||||
::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|
|
||||
1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|
|
||||
1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/x
|
||||
|
||||
belongs_to :domain, required: true
|
||||
|
||||
validates :hostname, presence: true
|
||||
validates :hostname, format: { with: HOSTNAME_REGEXP }, allow_blank: true
|
||||
validate :validate_ipv4_format
|
||||
validate :validate_ipv6_format
|
||||
validate :require_ip, if: :glue_record_required?
|
||||
|
||||
before_validation :normalize_attributes
|
||||
before_validation :check_puny_symbols
|
||||
|
@ -38,6 +51,39 @@ class Nameserver < ActiveRecord::Base
|
|||
}
|
||||
end
|
||||
|
||||
def to_s
|
||||
hostname
|
||||
end
|
||||
|
||||
def hostname=(hostname)
|
||||
self[:hostname] = SimpleIDN.to_unicode(hostname)
|
||||
self[:hostname_puny] = SimpleIDN.to_ascii(hostname)
|
||||
end
|
||||
|
||||
class << self
|
||||
def find_by_hash_params params
|
||||
params = params.with_indifferent_access
|
||||
rel = all
|
||||
rel = rel.where(hostname: params[:hostname])
|
||||
rel
|
||||
end
|
||||
|
||||
def hostnames
|
||||
pluck(:hostname)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def require_ip
|
||||
errors.add(:base, :ip_required) if ipv4.blank? && ipv6.blank?
|
||||
end
|
||||
|
||||
def glue_record_required?
|
||||
return unless hostname? && domain
|
||||
hostname.end_with?(domain.name)
|
||||
end
|
||||
|
||||
def normalize_attributes
|
||||
self.hostname = hostname.try(:strip).try(:downcase)
|
||||
self.ipv4 = Array(ipv4).reject(&:blank?).map(&:strip)
|
||||
|
@ -45,6 +91,8 @@ class Nameserver < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def check_label_length
|
||||
return unless hostname
|
||||
|
||||
hostname_puny.split('.').each do |label|
|
||||
errors.add(:hostname, :puny_to_long) if label.length > 63
|
||||
end
|
||||
|
@ -55,71 +103,15 @@ class Nameserver < ActiveRecord::Base
|
|||
errors.add(:hostname, :invalid) if hostname =~ regexp
|
||||
end
|
||||
|
||||
def to_s
|
||||
hostname
|
||||
end
|
||||
|
||||
def hostname=(hostname)
|
||||
self[:hostname] = SimpleIDN.to_unicode(hostname)
|
||||
self[:hostname_puny] = SimpleIDN.to_ascii(hostname)
|
||||
end
|
||||
|
||||
def val_ipv4
|
||||
regexp = /\A(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\z/
|
||||
def validate_ipv4_format
|
||||
ipv4.to_a.each do |ip|
|
||||
errors.add(:ipv4, :invalid) unless ip =~ regexp
|
||||
errors.add(:ipv4, :invalid) unless ip =~ IPV4_REGEXP
|
||||
end
|
||||
end
|
||||
def val_ipv6
|
||||
regexp = /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/
|
||||
|
||||
def validate_ipv6_format
|
||||
ipv6.to_a.each do |ip|
|
||||
errors.add(:ipv6, :invalid) unless ip =~ regexp
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
def replace_hostname_ends(domains, old_end, new_end)
|
||||
domains = domains.where('EXISTS(
|
||||
select 1 from nameservers ns where ns.domain_id = domains.id AND ns.hostname LIKE ?
|
||||
)', "%#{old_end}")
|
||||
|
||||
count, success_count = 0.0, 0.0
|
||||
domains.each do |d|
|
||||
ns_attrs = { nameservers_attributes: [] }
|
||||
|
||||
d.nameservers.each do |ns|
|
||||
next unless ns.hostname.end_with?(old_end)
|
||||
|
||||
hn = ns.hostname.chomp(old_end)
|
||||
ns_attrs[:nameservers_attributes] << {
|
||||
id: ns.id,
|
||||
hostname: "#{hn}#{new_end}"
|
||||
}
|
||||
end
|
||||
|
||||
success_count += 1 if d.update(ns_attrs)
|
||||
count += 1
|
||||
end
|
||||
|
||||
return 'replaced_none' if count == 0.0
|
||||
|
||||
prc = success_count / count
|
||||
|
||||
return 'replaced_all' if prc == 1.0
|
||||
'replaced_some'
|
||||
end
|
||||
|
||||
def find_by_hash_params params
|
||||
params = params.with_indifferent_access
|
||||
rel = all
|
||||
rel = rel.where(hostname: params[:hostname])
|
||||
# rel = rel.where(hostname: params[:hostname]) if params[:ipv4]
|
||||
# ignoring ips
|
||||
rel
|
||||
end
|
||||
|
||||
def hostnames
|
||||
pluck(:hostname)
|
||||
errors.add(:ipv6, :invalid) unless ip =~ IPV6_REGEXP
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -158,6 +158,20 @@ class Registrar < ActiveRecord::Base
|
|||
white_ips.api.pluck(:ipv4, :ipv6).flatten.include?(ip)
|
||||
end
|
||||
|
||||
# Audit log is needed, therefore no raw SQL
|
||||
def replace_nameservers(hostname, new_attributes)
|
||||
transaction do
|
||||
nameservers.where(hostname: hostname).find_each do |original_nameserver|
|
||||
new_nameserver = Nameserver.new
|
||||
new_nameserver.domain = original_nameserver.domain
|
||||
new_nameserver.attributes = new_attributes
|
||||
new_nameserver.save!
|
||||
|
||||
original_nameserver.destroy!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_defaults
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
<div class="page-header">
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<div class="col-sm-7">
|
||||
<h1><%= t '.header' %></h1>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3 text-right">
|
||||
<div class="col-sm-5 text-right">
|
||||
<%= link_to t('.new_btn'), new_registrar_domain_path, class: 'btn btn-primary' %>
|
||||
<%= link_to t('.transfer_btn'), new_registrar_domain_transfer_path, class: 'btn btn-default' %>
|
||||
<%= link_to t('.replace_nameserver_btn'), registrar_edit_registrar_nameserver_path,
|
||||
class: 'btn btn-default' %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
55
app/views/registrar/registrar_nameservers/_form.html.erb
Normal file
55
app/views/registrar/registrar_nameservers/_form.html.erb
Normal file
|
@ -0,0 +1,55 @@
|
|||
<%= form_tag registrar_update_registrar_nameserver_path, method: :put, class: 'form-horizontal' do %>
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= label_tag :old_hostname %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
<%= text_field_tag :old_hostname, params[:old_hostname], autofocus: true,
|
||||
required: true,
|
||||
spellcheck: false,
|
||||
class: 'form-control' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= label_tag :new_hostname %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
<%= text_field_tag :new_hostname, params[:new_hostname], required: true,
|
||||
spellcheck: false,
|
||||
class: 'form-control' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= label_tag :ipv4 %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<%= text_area_tag :ipv4, params[:ipv4], spellcheck: false, class: 'form-control' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= label_tag :ipv6 %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<%= text_area_tag :ipv6, params[:ipv6], spellcheck: false, class: 'form-control' %>
|
||||
<span class="help-block"><%= t '.ip_hint' %></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-5 col-md-offset-2 text-right">
|
||||
<button class="btn btn-warning">
|
||||
<%= t '.replace_btn' %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
11
app/views/registrar/registrar_nameservers/edit.html.erb
Normal file
11
app/views/registrar/registrar_nameservers/edit.html.erb
Normal file
|
@ -0,0 +1,11 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><%= link_to t('registrar.domains.index.header'), registrar_domains_path %></li>
|
||||
</ol>
|
||||
|
||||
<div class="page-header">
|
||||
<h1><%= t '.header' %></h1>
|
||||
</div>
|
||||
|
||||
<%= render 'registrar/domain_transfers/form/api_errors' %>
|
||||
|
||||
<%= render 'form' %>
|
Loading…
Add table
Add a link
Reference in a new issue