diff --git a/app/controllers/concerns/epp_requestable.rb b/app/controllers/concerns/epp_requestable.rb
new file mode 100644
index 000000000..d290c8e38
--- /dev/null
+++ b/app/controllers/concerns/epp_requestable.rb
@@ -0,0 +1,63 @@
+module EppRequestable
+ extend ActiveSupport::Concern
+
+ included do
+ # before_action :validate_epp_user, only: :create
+ end
+
+ def create
+ result = server.request(request_params[:payload])
+ render_success(data: { xml: result.force_encoding('UTF-8') })
+ rescue StandardError
+ handle_non_epp_errors(nil, I18n.t('errors.messages.epp_conn_error'))
+ end
+
+ private
+
+ # def validate_epp_user
+ # return unless handle_hello_request
+
+ # handle_login_request
+ # server.close_connection
+ # rescue OpenSSL::SSL::SSLError => e
+ # Rails.logger.error "INVALID CERT: #{e}"
+ # Rails.logger.error "INVALID CERT DEBUG INFO: epp_hostname: #{ENV['epp_hostname']}," \
+ # "port: #{ENV['epp_port']}, cert_path: #{ENV['cert_path']}, key_path: #{ENV['key_path']}"
+ # handle_non_epp_errors(nil, I18n.t('errors.messages.invalid_cert'))
+ # end
+
+ # def handle_hello_request
+ # res = server.open_connection
+ # unless Nokogiri::XML(res).css('greeting')
+ # server.close_connection # just in case
+ # handle_non_epp_errors(nil, I18n.t('errors.messages.failed_epp_conn')) and return false
+ # end
+ # true
+ # end
+
+ # def handle_login_request
+ # tag = current_user.username
+ # ex = EppXml::Session.new(cl_trid_prefix: tag)
+ # xml = ex.login(clID: { value: tag }, pw: { value: current_user.plain_text_password })
+ # res = server.send_request(xml)
+
+ # return if Nokogiri::XML(res).css('result').first['code'] == '1000'
+
+ # handle_non_epp_errors(nil, Nokogiri::XML(res).css('result').text)
+ # end
+
+ def server
+ client_cert = File.read(ENV['cert_path'])
+ client_key = File.read(ENV['key_path'])
+ port = ENV['epp_port'] || 700
+ @server ||= Epp::Server.new({ server: ENV['epp_hostname'], tag: current_user.username,
+ password: current_user.plain_text_password,
+ port: port,
+ cert: OpenSSL::X509::Certificate.new(client_cert),
+ key: OpenSSL::PKey::RSA.new(client_key) })
+ end
+
+ def request_params
+ params.require(:xml_console).permit(:payload)
+ end
+end
diff --git a/app/controllers/repp/v1/registrar/xml_console_controller.rb b/app/controllers/repp/v1/registrar/xml_console_controller.rb
new file mode 100644
index 000000000..cedf23819
--- /dev/null
+++ b/app/controllers/repp/v1/registrar/xml_console_controller.rb
@@ -0,0 +1,55 @@
+module Repp
+ module V1
+ module Registrar
+ class XmlConsoleController < BaseController
+ include EppRequestable
+
+ THROTTLED_ACTIONS = %i[load_xml].freeze
+ include Shunter::Integration::Throttle
+
+ PREFS = %w[domain-ee contact-ee eis epp-ee].freeze
+
+ SCHEMA_VERSIONS = {
+ 'epp-ee' => '1.0',
+ 'eis' => '1.0',
+ 'contact-ee' => '1.1',
+ 'default' => '1.2',
+ }.freeze
+
+ def load_xml
+ cl_trid = "#{current_user.username}-#{Time.zone.now.to_i}"
+ obj = ActionController::Base.helpers.sanitize(params[:obj])
+ epp_action = ActionController::Base.helpers.sanitize(params[:epp_action])
+ xml_dir_path = Rails.root.join('app/views/epp/sample_requests').to_s
+ xml = File.read("#{xml_dir_path}/#{obj}/#{epp_action}.xml")
+ xml = prepare_payload(xml, cl_trid)
+
+ render_success(data: { xml: xml })
+ end
+
+ private
+
+ def prepare_payload(xml, cl_trid)
+ PREFS.map do |pref|
+ xml = load_schema_by_prefix(pref, xml)
+ end
+
+ xml.gsub!('ABC-12345', "#{cl_trid}")
+ xml
+ end
+
+ def load_schema_by_prefix(pref, xml)
+ version = version_by_prefix(pref)
+ xml.gsub!("\"#{pref}\"",
+ "\"#{Xsd::Schema.filename(for_prefix: pref.to_s, for_version: version)}\"")
+ xml
+ end
+
+ def version_by_prefix(pref)
+ key = SCHEMA_VERSIONS.key?(pref) ? pref : 'default'
+ SCHEMA_VERSIONS[key]
+ end
+ end
+ end
+ end
+end
diff --git a/app/controllers/repp/v1/stats_controller.rb b/app/controllers/repp/v1/stats_controller.rb
index 480c81a6b..ae8489c34 100644
--- a/app/controllers/repp/v1/stats_controller.rb
+++ b/app/controllers/repp/v1/stats_controller.rb
@@ -90,6 +90,8 @@ module Repp
def calculate_market_share(domains_by_rar)
sum = domains_by_rar.values.sum
+ return domains_by_rar if sum.zero?
+
domains_by_rar.transform_values do |v|
value = v.to_f / sum * 100.0
value < 0.1 ? value.round(3) : value.round(1)
diff --git a/app/models/domain.rb b/app/models/domain.rb
index 2c2b363fa..f770b623f 100644
--- a/app/models/domain.rb
+++ b/app/models/domain.rb
@@ -65,7 +65,6 @@ class Domain < ApplicationRecord
statuses.include? DomainStatus::SERVER_REGISTRANT_CHANGE_PROHIBITED
end
-
# NB! contacts, admin_contacts, tech_contacts are empty for a new record
has_many :domain_contacts, dependent: :destroy
has_many :contacts, through: :domain_contacts, source: :contact
diff --git a/app/models/legal_document.rb b/app/models/legal_document.rb
index cafd04af7..e70fa2d12 100644
--- a/app/models/legal_document.rb
+++ b/app/models/legal_document.rb
@@ -1,4 +1,4 @@
-class LegalDocument < ApplicationRecord
+class LegalDocument < ApplicationRecord # rubocop:disable Metrics/ClassLength
include EppErrors
MIN_BODY_SIZE = (1.37 * 3.kilobytes).ceil
MAX_BODY_SIZE = 8.megabytes
@@ -14,7 +14,7 @@ class LegalDocument < ApplicationRecord
belongs_to :documentable, polymorphic: true
- validate :val_body_length, if: ->(file) { file.path.blank? }
+ validate :val_body_length, if: ->(file) { file.path.blank? && (Rails.env.production? || Rails.env.test?) }
before_create :add_creator
before_save :save_to_filesystem, if: :body
@@ -24,7 +24,7 @@ class LegalDocument < ApplicationRecord
'2308' => [
%i[body length_more_than],
%i[body length_less_than],
- ]
+ ],
}
end
@@ -41,12 +41,13 @@ class LegalDocument < ApplicationRecord
digest = Digest::SHA1.new.update(binary).to_s
loop do
- rand = SecureRandom.random_number.to_s.last(4)
- next if rand.to_i == 0 || rand.length < 4
- dir = "#{ENV['legal_documents_dir']}/#{Time.zone.now.strftime('%Y/%m/%d')}"
- FileUtils.mkdir_p(dir, mode: 0775)
- self.path = "#{dir}/#{Time.zone.now.to_formatted_s(:number)}_#{rand}.#{document_type}"
- break unless File.file?(path)
+ rand = SecureRandom.random_number.to_s.last(4)
+ next if rand.to_i.zero? || rand.length < 4
+
+ dir = "#{ENV['legal_documents_dir']}/#{Time.zone.now.strftime('%Y/%m/%d')}"
+ FileUtils.mkdir_p(dir, mode: 0775)
+ self.path = "#{dir}/#{Time.zone.now.to_formatted_s(:number)}_#{rand}.#{document_type}"
+ break unless File.file?(path)
end
File.open(path, 'wb') { |f| f.write(binary) } unless Rails.env.test?
@@ -69,50 +70,57 @@ class LegalDocument < ApplicationRecord
start = Time.zone.now.to_f
Rails.logger.info '-----> Removing legal documents duplicates'
count = 0
- modified = Array.new
+ modified = []
- LegalDocument.where(documentable_type: "Domain").where.not(checksum: [nil, ""]).find_each do |orig_legal|
+ LegalDocument.where(documentable_type: 'Domain')
+ .where.not(checksum: [nil, ''])
+ .find_each do |orig_legal|
next if modified.include?(orig_legal.checksum)
- next if !File.exist?(orig_legal.path)
+ next unless File.exist?(orig_legal.path)
+
modified.push(orig_legal.checksum)
- LegalDocument.where(documentable_type: "Domain", documentable_id: orig_legal.documentable_id).
- where(checksum: orig_legal.checksum).
- where.not(id: orig_legal.id).where.not(path: orig_legal.path).each do |new_legal|
- unless modified.include?(orig_legal.id)
- File.delete(new_legal.path) if File.exist?(new_legal.path)
- new_legal.update(path: orig_legal.path)
- count += 1
- Rails.logger.info "File #{new_legal.path} has been removed by Domain "\
- "#{new_legal.documentable_id}. Document id: #{new_legal.id}"
- end
+ LegalDocument.where(documentable_type: 'Domain', documentable_id: orig_legal.documentable_id)
+ .where(checksum: orig_legal.checksum)
+ .where.not(id: orig_legal.id)
+ .where.not(path: orig_legal.path).each do |new_legal|
+ next if modified.include?(orig_legal.id)
+
+ File.delete(new_legal.path) if File.exist?(new_legal.path)
+ new_legal.update(path: orig_legal.path)
+ count += 1
+ Rails.logger.info "File #{new_legal.path} has been removed by Domain "\
+ "#{new_legal.documentable_id}. Document id: #{new_legal.id}"
end
- contact_ids = Version::DomainVersion.where(item_id: orig_legal.documentable_id).distinct.
- pluck("object->>'registrant_id'", "object_changes->>'registrant_id'",
- "children->>'tech_contacts'", "children->>'admin_contacts'").flatten.uniq
- contact_ids = contact_ids.map{|id|
+ contact_ids = Version::DomainVersion.where(item_id: orig_legal.documentable_id).distinct
+ .pluck("object->>'registrant_id'",
+ "object_changes->>'registrant_id'",
+ "children->>'tech_contacts'",
+ "children->>'admin_contacts'")
+ .flatten.uniq
+ contact_ids = contact_ids.map do |id|
case id
- when Hash
- id["id"]
- when String
- JSON.parse(id) rescue id.to_i
- else
- id
- end
- }.flatten.compact.uniq
- LegalDocument.where(documentable_type: "Contact", documentable_id: contact_ids).
- where(checksum: orig_legal.checksum).where.not(path: orig_legal.path).each do |new_legal|
- unless modified.include?(orig_legal.id)
- File.delete(new_legal.path) if File.exist?(new_legal.path)
- new_legal.update(path: orig_legal.path)
- count += 1
- Rails.logger.info "File #{new_legal.path} has been removed by Contact "\
- "#{new_legal.documentable_id}. Document id: #{new_legal.id}"
+ when Hash
+ id['id']
+ when String
+ JSON.parse(id) rescue id.to_i
+ else
+ id
end
+ end.flatten.compact.uniq
+ LegalDocument.where(documentable_type: 'Contact', documentable_id: contact_ids)
+ .where(checksum: orig_legal.checksum)
+ .where.not(path: orig_legal.path).each do |new_legal|
+ next if modified.include?(orig_legal.id)
+
+ File.delete(new_legal.path) if File.exist?(new_legal.path)
+ new_legal.update(path: orig_legal.path)
+ count += 1
+ Rails.logger.info "File #{new_legal.path} has been removed by Contact "\
+ "#{new_legal.documentable_id}. Document id: #{new_legal.id}"
end
end
Rails.logger.info "-----> Duplicates fixed for #{count} rows in #{(Time.zone.now.to_f - start).round(2)} seconds"
-
end
end
diff --git a/app/views/epp/sample_requests/contact/check.xml b/app/views/epp/sample_requests/contact/check.xml
new file mode 100644
index 000000000..f4c10d8bd
--- /dev/null
+++ b/app/views/epp/sample_requests/contact/check.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ sh8013
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/contact/check_multiple.xml b/app/views/epp/sample_requests/contact/check_multiple.xml
new file mode 100644
index 000000000..bdcff03dd
--- /dev/null
+++ b/app/views/epp/sample_requests/contact/check_multiple.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ sh8013
+ sh13
+ vsdfvq
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/contact/create.xml b/app/views/epp/sample_requests/contact/create.xml
new file mode 100644
index 000000000..fc60b8311
--- /dev/null
+++ b/app/views/epp/sample_requests/contact/create.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+ Sillius Soddus
+
+ 123 Example Dr.
+ Suite 100
+
+ Megaton
+ F3
+ 201-33
+ EE
+
+
+ +372.1234567
+ example@test.example
+
+
+
+
+ 123
+
+ dGVzdCBmYWlsCg==
+
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/contact/delete.xml b/app/views/epp/sample_requests/contact/delete.xml
new file mode 100644
index 000000000..28b50af64
--- /dev/null
+++ b/app/views/epp/sample_requests/contact/delete.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ sh8013
+
+ wrong-one
+
+
+
+
+
+
+ dGVzdCBmYWlsCg==
+
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/contact/info.xml b/app/views/epp/sample_requests/contact/info.xml
new file mode 100644
index 000000000..44e5d5a1e
--- /dev/null
+++ b/app/views/epp/sample_requests/contact/info.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ sh8013
+
+ Aas34fq
+
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/contact/update_chg.xml b/app/views/epp/sample_requests/contact/update_chg.xml
new file mode 100644
index 000000000..61ea43202
--- /dev/null
+++ b/app/views/epp/sample_requests/contact/update_chg.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+ sh8013
+
+
+ John Doe
+
+ 123 Example Dr.
+ Suite 100
+ Dulles
+ VA
+ 20166-6503
+ EE
+
+
+ +123.7035555555
+ jdoe@example.com
+
+ 2fooBAR
+
+
+
+
+
+
+
+ dGVzdCBmYWlsCg==
+
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/domain/check.xml b/app/views/epp/sample_requests/domain/check.xml
new file mode 100644
index 000000000..06492bcfe
--- /dev/null
+++ b/app/views/epp/sample_requests/domain/check.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ example.ee
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/domain/client_hold.xml b/app/views/epp/sample_requests/domain/client_hold.xml
new file mode 100644
index 000000000..68f0b778e
--- /dev/null
+++ b/app/views/epp/sample_requests/domain/client_hold.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ example.ee
+
+
+
+
+
+ timo-1579351654
+
+
diff --git a/app/views/epp/sample_requests/domain/create.xml b/app/views/epp/sample_requests/domain/create.xml
new file mode 100644
index 000000000..f57fcfe30
--- /dev/null
+++ b/app/views/epp/sample_requests/domain/create.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+ example.ee
+ 1
+
+
+ ns1.example.net
+
+
+ ns2.example.net
+ 192.0.2.2
+ 1080:0:0:0:8:800:200C:417A
+
+
+ jd1234
+ sh8013
+ sh8013
+ sh801333
+
+
+
+
+
+ 257
+ 3
+ 8
+ AwEAAddt2AkLfYGKgiEZB5SmIF8EvrjxNMH6HtxWEA4RJ9Ao6LCWheg8
+
+
+
+
+ dGVzdCBmYWlsCg==
+
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/domain/delete.xml b/app/views/epp/sample_requests/domain/delete.xml
new file mode 100644
index 000000000..f47bb79eb
--- /dev/null
+++ b/app/views/epp/sample_requests/domain/delete.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+ example.ee
+
+
+
+
+
+ dGVzdCBmYWlsCg==
+
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/domain/info.xml b/app/views/epp/sample_requests/domain/info.xml
new file mode 100644
index 000000000..210396c3b
--- /dev/null
+++ b/app/views/epp/sample_requests/domain/info.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ example.ee
+
+ 2fooBAR
+
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/domain/renew.xml b/app/views/epp/sample_requests/domain/renew.xml
new file mode 100644
index 000000000..6ef479468
--- /dev/null
+++ b/app/views/epp/sample_requests/domain/renew.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ example.ee
+ 2014-08-07
+ 1
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/domain/transfer.xml b/app/views/epp/sample_requests/domain/transfer.xml
new file mode 100644
index 000000000..6ab951eeb
--- /dev/null
+++ b/app/views/epp/sample_requests/domain/transfer.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ example.ee
+
+ 2BARfoo
+
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/domain/update.xml b/app/views/epp/sample_requests/domain/update.xml
new file mode 100644
index 000000000..c087245e7
--- /dev/null
+++ b/app/views/epp/sample_requests/domain/update.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+ example.ee
+
+
+
+ ns1.example.com
+
+
+ ns2.example.com
+
+
+ mak21
+
+
+
+
+ ns1.example.net
+
+
+ mak21
+
+
+ mak21
+
+ newpw
+
+
+
+
+
+
+
+
+ 257
+ 3
+ 8
+ 700b97b591ed27ec2590d19f06f88bba700b97b591ed27ec2590d19f
+
+
+
+
+
+ dGVzdCBmYWlsCg==
+
+
+
+ ABC-12345
+
+
diff --git a/app/views/epp/sample_requests/poll/poll.xml b/app/views/epp/sample_requests/poll/poll.xml
new file mode 100644
index 000000000..5ffed010e
--- /dev/null
+++ b/app/views/epp/sample_requests/poll/poll.xml
@@ -0,0 +1,7 @@
+
+
+
+
+ ABC-12345
+
+
diff --git a/config/application.yml.sample b/config/application.yml.sample
index dffeea5be..61bf6f223 100644
--- a/config/application.yml.sample
+++ b/config/application.yml.sample
@@ -61,6 +61,13 @@ contact_org_enabled: 'false'
# System default for legal document types is: pdf,asice,sce,asics,scs,adoc,edoc,bdoc,ddoc,zip,rar,gz,tar,7z,odt,doc,docx
# legal_document_types: "pdf,asice,sce,asics,scs,adoc,edoc,bdoc,ddoc,zip,rar,gz,tar,7z,odt,doc,docx"
+#
+# REGISTRAR configuration
+#
+epp_port: '700'
+cert_path: '/opt/ca/certs/webclient.crt.pem'
+key_path: '/opt/ca/private/webclient.key.pem'
+epp_hostname: 'epp_proxy'
repp_url: 'http://epp:3000/repp/v1/'
# Estonian Company Register
diff --git a/config/locales/en.yml b/config/locales/en.yml
index d42efd0a5..7a6fa2eb9 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -187,6 +187,9 @@ en:
required_ident_attribute_missing: "Required ident attribute missing: %{key}"
invalid_iso31661_alpha2: does not conform to ISO 3166-1 alpha-2 standard
invalid_iso8601_date: has invalid date format YYYY-MM-DD (ISO 8601)
+ invalid_cert: 'Invalid certificate'
+ failed_epp_conn: 'Failed to open connection to EPP server!'
+ epp_conn_error: 'CONNECTION ERROR - Is the EPP server running?'
code: 'Code'
action: 'Action'
diff --git a/config/routes.rb b/config/routes.rb
index 21fc16224..d8d52f322 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -106,7 +106,7 @@ Rails.application.routes.draw do
end
end
namespace :registrar do
- resources :notifications, only: [:index, :show, :update] do
+ resources :notifications, only: %i[index show update] do
collection do
get '/all_notifications', to: 'notifications#all_notifications'
end
@@ -128,6 +128,11 @@ Rails.application.routes.draw do
post '/tara_callback', to: 'auth#tara_callback'
end
end
+ resource :xml_console, controller: 'xml_console', only: %i[create] do
+ collection do
+ get 'load_xml'
+ end
+ end
end
resources :domains, constraints: { id: /.*/ } do
resources :nameservers, only: %i[index create destroy], constraints: { id: /.*/ }, controller: 'domains/nameservers'
@@ -136,8 +141,8 @@ Rails.application.routes.draw do
resources :renew, only: %i[create], constraints: { id: /.*/ }, controller: 'domains/renews'
resources :transfer, only: %i[create], constraints: { id: /.*/ }, controller: 'domains/transfers'
resources :statuses, only: %i[update destroy], constraints: { id: /.*/ }, controller: 'domains/statuses'
- match "dnssec", to: "domains/dnssec#destroy", via: "delete", defaults: { id: nil }
- match "contacts", to: "domains/contacts#destroy", via: "delete", defaults: { id: nil }
+ match 'dnssec', to: 'domains/dnssec#destroy', via: 'delete', defaults: { id: nil }
+ match 'contacts', to: 'domains/contacts#destroy', via: 'delete', defaults: { id: nil }
collection do
get ':id/transfer_info', to: 'domains#transfer_info', constraints: { id: /.*/ }
post 'transfer', to: 'domains#transfer'
diff --git a/test/integration/repp/v1/registrar/xml_console_test.rb b/test/integration/repp/v1/registrar/xml_console_test.rb
new file mode 100644
index 000000000..db37dbebc
--- /dev/null
+++ b/test/integration/repp/v1/registrar/xml_console_test.rb
@@ -0,0 +1,108 @@
+require 'test_helper'
+
+class ReppV1RegistrarXmlConsoleTest < ActionDispatch::IntegrationTest
+ def setup
+ @user = users(:api_bestnames)
+ token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
+ token = "Basic #{token}"
+
+ @auth_headers = { 'Authorization' => token }
+ adapter = ENV['shunter_default_adapter'].constantize.new
+ adapter&.clear!
+ end
+
+ def test_load_schema_path
+ get load_xml_repp_v1_registrar_xml_console_path, params: { obj: 'domain', epp_action: 'update' },
+ headers: @auth_headers
+
+ assert_response :ok
+ json = JSON.parse(response.body, symbolize_names: true)
+ assert_equal update_payload, json[:data][:xml]
+ end
+
+ # TO BE REFACTORED
+ # def test_check_schema_path
+ # @auth_headers['Content-Type'] = 'application/json'
+ # params = { xml_console: { payload: payload } }
+ # post repp_v1_registrar_xml_console_path, params: params.to_json,
+ # headers: @auth_headers
+
+ # assert_response :ok
+ # end
+
+ private
+
+ def payload
+ <<~XML
+
+
+
+
+
+ auction.test
+
+
+
+
+ XML
+ end
+
+ def update_payload
+ <<~XML
+
+
+
+
+
+ example.ee
+
+
+
+ ns1.example.com
+
+
+ ns2.example.com
+
+
+ mak21
+
+
+
+
+ ns1.example.net
+
+
+ mak21
+
+
+ mak21
+
+ newpw
+
+
+
+
+
+
+
+
+ 257
+ 3
+ 8
+ 700b97b591ed27ec2590d19f06f88bba700b97b591ed27ec2590d19f
+
+
+
+
+
+ dGVzdCBmYWlsCg==
+
+
+
+ test_bestnames-#{Time.zone.now.to_i}
+
+
+ XML
+ end
+end
\ No newline at end of file