Init depp refactor

This commit is contained in:
Priit Tark 2015-04-08 14:05:05 +03:00
parent f3c9e0aecc
commit 3fe47973e6
156 changed files with 191 additions and 1662 deletions

View file

287
app/models/depp/contact.rb Normal file
View file

@ -0,0 +1,287 @@
module Depp
class Contact
include ActiveModel::Model
attr_accessor :id, :name, :email, :phone, :org_name,
:ident, :ident_type, :ident_country_code,
:street, :city, :zip, :state, :country_code,
:password, :legal_document, :statuses, :code
DISABLED = 'Disabled'
DISCLOSURE_TYPES = [DISABLED, '1', '0']
TYPES = %w( bic priv birthday )
SELECTION_TYPES = [
['Business code', 'bic'],
['Personal identification code', 'priv'],
['Birthday', 'birthday']
]
class << self
attr_reader :epp_xml, :user
# rubocop: disable Metrics/MethodLength
def new_from_params(params)
new(
id: params[:code],
code: params[:code],
email: params[:email],
phone: params[:phone],
ident: params[:ident],
ident_type: params[:ident_type],
ident_country_code: params[:ident_country_code],
# postalInfo
name: params[:name],
org_name: params[:org_name],
# address
street: params[:street],
city: params[:city],
zip: params[:zip],
state: params[:state],
country_code: params[:country_code]
)
end
# rubocop: enable Metrics/MethodLength
def find_by_id(id)
data = info_xml(id)
res = data.css('epp response resData infData')
new(
id: res.css('id').text,
code: res.css('id').text,
email: res.css('email').text,
phone: res.css('voice').text,
ident: res.css('ident').text,
ident_type: res.css('ident').first.try(:attributes).try(:[], 'type').try(:value),
ident_country_code: res.css('ident').first.try(:attributes).try(:[], 'cc').try(:value),
# postalInfo
name: res.css('postalInfo name').text,
org_name: res.css('postalInfo org').text,
# address
street: res.css('postalInfo addr street').text,
city: res.css('postalInfo addr city').text,
zip: res.css('postalInfo addr pc').text,
state: res.css('postalInfo addr sp').text,
country_code: res.css('postalInfo addr cc').text,
# authInfo
password: res.css('authInfo pw').text,
# statuses
statuses: data.css('status').map { |s| [s['s'], s.text] }
)
end
def user=(user)
@user = user
@epp_xml = EppXml::Contact.new(cl_trid_prefix: user.tag)
end
def info_xml(id, password = nil)
xml = epp_xml.info(
id: { value: id },
authInfo: { pw: { value: password } }
)
user.request(xml)
end
def construct_check_hash_from_data(data)
res = data.css('epp response resData chkData cd')
@contacts = []
res.each do |_r|
id = res.css('id').try(:text)
reason = res.css('reason').present? ? res.css('reason').text : I18n.t(:available)
@contacts << { id: id, reason: reason }
end
@contacts
end
def contact_id_from_xml(data)
id = data.css('epp response resData creData id').text
id.blank? ? nil : id
end
def construct_create_disclosure_xml(cph, flag)
xml = { disclose: {} }
cph.each do |k, v|
xml[:disclose][k] = {}
xml[:disclose][k][:value] = v
end
xml[:disclose][:attrs] = {}
xml[:disclose][:attrs][:flag] = flag
xml.with_indifferent_access
end
def extract_disclosure_hash(cpd) # cpd = contact_params[:disclose]
return {} unless cpd
cpd = cpd.delete_if { |k, v| v if v != '1' && k == 'flag' }
cpd
end
def extract_info_disclosure(data)
hash = {}
data.css('disclose').each do |d|
flag = d.attributes['flag'].value
next unless flag
hash[flag] = {}
d.children.each do |c|
hash[flag][c.name] = flag if %w( name email fax voice addr org_name ).include?(c.name)
end
end
hash
end
end
def initialize(attributes = {})
super
self.country_code = 'EE' if country_code.blank?
self.ident_type = 'bic' if ident_type.blank?
self.ident_country_code = 'EE' if ident_country_code.blank?
end
def save
create_xml = Depp::Contact.epp_xml.create(
{
id: { value: code },
email: { value: email },
voice: { value: phone },
postalInfo: {
name: { value: name },
org: { value: org_name },
addr: {
street: { value: street },
city: { value: city },
pc: { value: zip },
sp: { value: state },
cc: { value: country_code }
}
}
},
extension_xml
)
data = Depp::Contact.user.request(create_xml)
self.id = data.css('id').text
handle_errors(data)
end
# rubocop: disable Metrics/MethodLength
def update_attributes(params)
self.ident_country_code = params[:ident_country_code]
self.ident_type = params[:ident_type]
self.ident = params[:ident]
self.name = params[:name]
self.email = params[:email]
self.phone = params[:phone]
self.org_name = params[:org_name]
self.street = params[:street]
self.city = params[:city]
self.zip = params[:zip]
self.state = params[:state]
self.country_code = params[:country_code]
update_xml = Depp::Contact.epp_xml.update(
{
id: { value: id },
chg: {
voice: { value: phone },
email: { value: email },
postalInfo: {
name: { value: name },
org: { value: org_name },
addr: {
street: { value: street },
city: { value: city },
pc: { value: zip },
sp: { value: state },
cc: { value: country_code }
}
}
},
authInfo: {
pw: { value: password }
}
},
extension_xml
)
data = Depp::Contact.user.request(update_xml)
handle_errors(data)
end
# rubocop: enable Metrics/MethodLength
def delete
delete_xml = Contact.epp_xml.delete(
{
id: { value: id },
authInfo: { pw: { value: password } }
},
extension_xml
)
data = Depp::Contact.user.request(delete_xml)
handle_errors(data)
end
def extension_xml
ident_xml.merge(legal_document_xml)
end
def ident_xml
{
_anonymus: [
ident: { value: ident, attrs: { type: ident_type, cc: ident_country_code } }
]
}
end
def legal_document_xml
return {} if legal_document.blank?
type = legal_document.original_filename.split('.').last.downcase
{
_anonymus: [
legalDocument: { value: Base64.encode64(legal_document.read), attrs: { type: type } }
]
}
end
def check(id)
xml = epp_xml.check(id: { value: id })
current_user.request(xml)
end
def country_name
Country.new(country_code)
end
def bic?
ident_type == 'bic'
end
def priv?
ident_type == 'priv'
end
def persisted?
id.present?
end
def handle_errors(data)
data.css('result').each do |x|
success_codes = %(1000, 1300, 1301)
next if success_codes.include?(x['code'])
message = "#{x.css('msg').text} #{x.css('value').text}"
attr = message.split('[').last.strip.sub(']', '') if message.include?('[')
attr = :base if attr.nil?
attr = 'phone' if attr == 'voice'
errors.add(attr, message)
end
errors.blank?
end
end
end

25
app/models/depp/dnskey.rb Normal file
View file

@ -0,0 +1,25 @@
module Depp
class Dnskey
FLAGS = [
['0 - not for DNSSEC validation', 0],
['256 - ZSK', 256],
['257 - KSK', 257]
]
ALGORITHMS = [
['3 - DSA/SHA-1', 3],
['5 - RSA/SHA-1', 5],
['6 - DSA-NSEC3-SHA1', 6],
['7 - RSASHA1-NSEC3-SHA1', 7],
['8 - RSA/SHA-256', 8],
['252 - Reserved for Indirect Keys', 252],
['253 - Private algorithm', 253],
['254 - Private algorithm OID', 254],
['255 - Reserved', 255]
]
PROTOCOLS = [3]
DS_DIGEST_TYPES = [1, 2]
end
end

300
app/models/depp/domain.rb Normal file
View file

@ -0,0 +1,300 @@
module Depp
class Domain
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :name, :current_user, :epp_xml
DOMAIN_STATUSES = %w(
clientDeleteProhibited
clientHold
clientRenewProhibited
clientTransferProhibited
clientUpdateProhibited
)
def initialize(args = {})
self.current_user = args[:current_user]
self.epp_xml = EppXml::Domain.new(cl_trid_prefix: current_user.tag)
end
def info(domain_name)
xml = epp_xml.info(name: { value: domain_name })
current_user.request(xml)
end
def check(domain_name)
xml = epp_xml.check(
_anonymus: [
name: { value: domain_name }
]
)
current_user.request(xml)
end
def create(domain_params)
xml = epp_xml.create({
name: { value: domain_params[:name] },
registrant: { value: domain_params[:registrant] },
period: { value: domain_params[:period], attrs: { unit: domain_params[:period_unit] } },
ns: Domain.create_nameservers_hash(domain_params),
_anonymus: Domain.create_contacts_hash(domain_params)
}, {
_anonymus: Domain.create_dnskeys_hash(domain_params)
}, Domain.construct_custom_params_hash(domain_params))
current_user.request(xml)
end
def update(domain_params)
data = current_user.request(epp_xml.info(name: { value: domain_params[:name] }))
old_domain_params = Depp::Domain.construct_params_from_server_data(data)
xml = epp_xml.update(
Depp::Domain.construct_edit_hash(domain_params, old_domain_params),
Depp::Domain.construct_ext_edit_hash(domain_params, old_domain_params),
Depp::Domain.construct_custom_params_hash(domain_params)
)
current_user.request(xml)
end
def delete(domain_params)
xml = epp_xml.delete({
name: { value: domain_params[:name] }
}, Depp::Domain.construct_custom_params_hash(domain_params))
current_user.request(xml)
end
def renew(params)
current_user.request(epp_xml.renew(
name: { value: params[:domain_name] },
curExpDate: { value: params[:cur_exp_date] },
period: { value: params[:period], attrs: { unit: params[:period_unit] } }
))
end
def transfer(params)
op = params[:query] ? 'query' : nil
op = params[:approve] ? 'approve' : op
op = params[:reject] ? 'reject' : op
current_user.request(epp_xml.transfer({
name: { value: params[:domain_name] },
authInfo: { pw: { value: params[:password] } }
}, op, Domain.construct_custom_params_hash(params)))
end
def confirm_keyrelay(domain_params)
xml = epp_xml.update({
name: { value: domain_params[:name] }
}, {
add: Domain.create_dnskeys_hash(domain_params)
})
current_user.request(xml)
end
def confirm_transfer(domain_params)
data = current_user.request(epp_xml.info(name: { value: domain_params[:name] }))
pw = data.css('pw').text
xml = epp_xml.transfer({
name: { value: domain_params[:name] },
authInfo: { pw: { value: pw } }
}, 'approve')
current_user.request(xml)
end
class << self
def default_params
ret = {}
ret[:contacts_attributes] ||= {}
ENV['default_admin_contacts_count'].to_i.times do |i|
ret[:contacts_attributes][i] = { code: '', type: 'admin' }
end
ret[:nameservers_attributes] ||= {}
ENV['default_nameservers_count'].to_i.times do |i|
ret[:nameservers_attributes][i] = {}
end
ret[:dnskeys_attributes] ||= { 0 => {} }
ret[:statuses_attributes] ||= { 0 => {} }
ret.with_indifferent_access
end
def construct_params_from_server_data(data) # rubocop:disable Metrics/MethodLength
ret = default_params
ret[:name] = data.css('name').text
ret[:registrant] = data.css('registrant').text
data.css('contact').each_with_index do |x, i|
ret[:contacts_attributes][i] = { code: x.text, type: x['type'] }
end
data.css('hostAttr').each_with_index do |x, i|
ret[:nameservers_attributes][i] = {
hostname: x.css('hostName').text,
ipv4: x.css('hostAddr[ip="v4"]').text,
ipv6: x.css('hostAddr[ip="v6"]').text
}
end
data.css('dsData').each_with_index do |x, i|
ds = {
ds_key_tag: x.css('keyTag').first.try(:text),
ds_alg: x.css('alg').first.try(:text),
ds_digest_type: x.css('digestType').first.try(:text),
ds_digest: x.css('digest').first.try(:text)
}
kd = x.css('keyData').first
ds.merge!({
flags: kd.css('flags').first.try(:text),
protocol: kd.css('protocol').first.try(:text),
alg: kd.css('alg').first.try(:text),
public_key: kd.css('pubKey').first.try(:text)
}) if kd
ret[:dnskeys_attributes][i] = ds
end
data.css('status').each_with_index do |x, i|
next unless DOMAIN_STATUSES.include?(x['s'])
ret[:statuses_attributes][i] = {
code: x['s'],
description: x.text
}
end
ret
end
def construct_custom_params_hash(domain_params)
custom_params = {}
if domain_params[:legal_document].present?
type = domain_params[:legal_document].original_filename.split('.').last.downcase
custom_params = {
_anonymus: [
legalDocument: { value: Base64.encode64(domain_params[:legal_document].read), attrs: { type: type } }
]
}
end
custom_params
end
def construct_edit_hash(domain_params, old_domain_params)
contacts = create_contacts_hash(domain_params) - create_contacts_hash(old_domain_params)
statuses = create_statuses_hash(domain_params) - create_statuses_hash(old_domain_params)
add_anon = contacts + statuses
contacts = create_contacts_hash(old_domain_params) - create_contacts_hash(domain_params)
statuses = create_statuses_hash(old_domain_params) - create_statuses_hash(domain_params)
rem_anon = contacts + statuses
if domain_params[:registrant] != old_domain_params[:registrant]
chg = [{ registrant: { value: domain_params[:registrant] } }]
end
{
name: { value: domain_params[:name] },
chg: chg,
add: [
{ ns: create_nameservers_hash(domain_params) - create_nameservers_hash(old_domain_params) },
{ _anonymus: add_anon }
],
rem: [
{ ns: create_nameservers_hash(old_domain_params) - create_nameservers_hash(domain_params) },
{ _anonymus: rem_anon }
]
}
end
def construct_ext_edit_hash(domain_params, old_domain_params)
{
add: create_dnskeys_hash(domain_params) - create_dnskeys_hash(old_domain_params),
rem: create_dnskeys_hash(old_domain_params) - create_dnskeys_hash(domain_params)
}
end
def create_nameservers_hash(domain_params)
ret = []
domain_params[:nameservers_attributes].each do |_k, v|
next if v['hostname'].blank?
host_attr = []
host_attr << { hostName: { value: v['hostname'] } }
host_attr << { hostAddr: { value: v['ipv4'], attrs: { ip: 'v4' } } } if v['ipv4'].present?
host_attr << { hostAddr: { value: v['ipv6'], attrs: { ip: 'v6' } } } if v['ipv6'].present?
ret << { hostAttr: host_attr }
end
ret
end
def create_contacts_hash(domain_params)
ret = []
domain_params[:contacts_attributes].each do |_k, v|
next if v['code'].blank?
ret << {
contact: { value: v['code'], attrs: { type: v['type'] } }
}
end
ret
end
def create_dnskeys_hash(domain_params)
ret = []
domain_params[:dnskeys_attributes].each do |_k, v|
if v['ds_key_tag'].blank?
kd = create_key_data_hash(v)
ret << {
keyData: kd
} if kd
else
ret << {
dsData: [
keyTag: { value: v['ds_key_tag'] },
alg: { value: v['ds_alg'] },
digestType: { value: v['ds_digest_type'] },
digest: { value: v['ds_digest'] },
keyData: create_key_data_hash(v)
]
}
end
end
ret
end
def create_key_data_hash(key_data_params)
return nil if key_data_params['public_key'].blank?
{
flags: { value: key_data_params['flags'] },
protocol: { value: key_data_params['protocol'] },
alg: { value: key_data_params['alg'] },
pubKey: { value: key_data_params['public_key'] }
}
end
def create_statuses_hash(domain_params)
ret = []
domain_params[:statuses_attributes].each do |_k, v|
next if v['code'].blank?
ret << {
status: { value: v['description'], attrs: { s: v['code'] } }
}
end
ret
end
end
end
end

View file

@ -0,0 +1,41 @@
module Depp
class Keyrelay
attr_accessor :current_user, :epp_xml
def initialize(args = {})
self.current_user = args[:current_user]
self.epp_xml = EppXml::Keyrelay.new(cl_trid_prefix: current_user.tag)
end
def keyrelay(params) # rubocop:disable Metrics/MethodLength
custom_params = {}
if params[:legal_document].present?
type = params[:legal_document].original_filename.split('.').last.downcase
custom_params = {
_anonymus: [
legalDocument: { value: Base64.encode64(params[:legal_document].read), attrs: { type: type } }
]
}
end
xml = epp_xml.keyrelay({
name: { value: params['domain_name'] },
keyData: {
flags: { value: params['key_data_flags'] },
protocol: { value: params['key_data_protocol'] },
alg: { value: params['key_data_alg'] },
pubKey: { value: params['key_data_public_key'] }
},
authInfo: {
pw: { value: params['password'] }
},
expiry: {
relative: { value: params['expiry_relative'] },
absolute: { value: params['expiry_absolute'] }
}
}, custom_params)
current_user.request(xml)
end
end
end

92
app/models/depp/user.rb Normal file
View file

@ -0,0 +1,92 @@
module Depp
class User
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :tag, :password, :pki
validates :tag, :password, presence: true
validate :validate_existance_in_server
def initialize(args = {})
args.each { |k, v| send(k.to_s + '=', v) }
end
def server
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
port = Rails.env.test? ? 701 : ENV['epp_port']
@server_cache ||= Epp::Server.new({
server: ENV['epp_hostname'],
tag: tag,
password: password,
port: port,
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)
})
end
def request(xml)
Nokogiri::XML(server.request(xml)).remove_namespaces!
end
def repp_request(path, params = {})
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
uri = URI.parse("#{ENV['repp_url']}#{path}")
uri.query = URI.encode_www_form(params)
req = Net::HTTP::Get.new(uri)
req.basic_auth tag, password
res = 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(req)
end
ret = OpenStruct.new(code: res.code)
ret.parsed_body = JSON.parse(res.body) if res.body.present?
if ret.parsed_body && ret.parsed_body['error']
ret.message = ret.parsed_body['error']
else
ret.message = res.message
end
ret
end
private
def validate_existance_in_server
return if errors.any?
res = server.open_connection
unless Nokogiri::XML(res).css('greeting')
errors.add(:base, :failed_to_open_connection_to_epp_server)
server.close_connection # just in case
return
end
ex = EppXml::Session.new(cl_trid_prefix: tag)
xml = ex.login(clID: { value: tag }, pw: { value: password })
res = server.send_request(xml)
if Nokogiri::XML(res).css('result').first['code'] != '1000'
errors.add(:base, :authorization_error)
end
server.close_connection
rescue OpenSSL::SSL::SSLError
errors.add(:base, :invalid_cert)
end
end
end