Class: EPPClient::AFNIC

Inherits:
Base
  • Object
show all
Includes:
RGP, SecDNS
Defined in:
lib/epp-client/afnic.rb

Constant Summary collapse

SCHEMAS_AFNIC =
%w[
  frnic-1.2
]

Instance Method Summary collapse

Constructor Details

#initialize(args) ⇒ AFNIC

Sets the default for AFNIC, that is, server and port, according to AFNIC’s documentation. www.afnic.fr/doc/interface/epp

Optional Attributes

:test

sets the server to be the test server.



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/epp-client/afnic.rb', line 23

def initialize(args)
  if args.delete(:test) == true
	args[:server] ||= 'epp.sandbox.nic.fr'
  else
	args[:server] ||= 'epp.nic.fr'
  end
  @services = EPPClient::SCHEMAS_URL.values_at('domain', 'contact')
  args[:port] ||= 700
  super(args)
  @extensions << EPPClient::SCHEMAS_URL['frnic']
end

Instance Method Details

#contact_afnic_qualification(xml) ⇒ Object

:nodoc:



482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'lib/epp-client/afnic.rb', line 482

def contact_afnic_qualification(xml) #:nodoc:
  contact = xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:quaData/frnic:contact', EPPClient::SCHEMAS_URL)
  ret = {:id => contact.xpath('frnic:id', EPPClient::SCHEMAS_URL).text}
  qP = contact.xpath('frnic:qualificationProcess', EPPClient::SCHEMAS_URL)
  ret[:qualificationProcess] = {:s => qP.attr('s').value}
  ret[:qualificationProcess][:lang] = qP.attr('lang').value if qP.attr('lang')
  if (leI = contact.xpath('frnic:legalEntityInfos', EPPClient::SCHEMAS_URL)).size > 0
	ret[:legalEntityInfos] = legalEntityInfos(leI)
  end
  reach = contact.xpath('frnic:reachability', EPPClient::SCHEMAS_URL)
  ret[:reachability] = {:reStatus => reach.xpath('frnic:reStatus', EPPClient::SCHEMAS_URL).text}
  if (voice = reach.xpath('frnic:voice', EPPClient::SCHEMAS_URL)).size > 0
	ret[:reachability][:voice] = voice.text
  end
  if (email = reach.xpath('frnic:email', EPPClient::SCHEMAS_URL)).size > 0
	ret[:reachability][:email] = email.text
  end
  ret
end

#contact_create(contact) ⇒ Object

Extends the EPPClient::Contact#contact_create so that the specific AFNIC create informations can be sent, the additionnal informations are :

either :

:legalEntityInfos

indicating that the contact is an organisation with the following informations :

:idStatus

indicates the identification process status.

:legalStatus

should be either company, association or other.

:siren

contains the SIREN number of the organisation.

:VAT

is optional and contains the VAT number of the organisation.

:trademark

is optional and contains the trademark number of the organisation.

:DUNS

is optional and contains the Data Universal Numbering System number of the organisation.

:local

is optional and contains an identifier local to the eligible country.

:asso

indicates the organisation is an association and contains either a waldec or a decl and a publ :

:waldec

contains the waldec id of the association.

:decl

optionally indicate the date of the association was declared at the prefecture.

:publ

contains informations regarding the publication in the “Journal Officiel” :

:date

the date of publication.

:page

the page the announce is on.

:announce

the announce number on the page (optional).

:individualInfos

indicating that the contact is a person with the following informations :

:idStatus

indicates the identification process status.

:birthDate

the date of birth of the contact.

:birthCity

the city of birth of the contact.

:birthPc

the postal code of the city of birth.

:birthCc

the country code of the place of birth.

Additionnaly, when the contact is a person, there can be the following informations :

:firstName

the first name of the person. (The last name being stored in the name field in the postalInfo.)

:list

with the value of restrictedPublication mean that the element diffusion should be restricted.

Optionnaly, there can be :

:reachable

the contact is reachable through the optional :media.

The returned information contains new keys :

:idStatus

indicates the identification process status. It’s only present when the created contact was created with the :individualInfos or :legalEntityInfos extensions.

:nhStatus

is a boolean indicating wether the contact is really new, or if there was already a contact with the exact same informations in the database, in which case, it has been returned.



366
367
368
# File 'lib/epp-client/afnic.rb', line 366

def contact_create(contact)
  super # placeholder so that I can add some doc
end

#contact_create_process(xml) ⇒ Object

:nodoc:



370
371
372
373
374
375
376
377
# File 'lib/epp-client/afnic.rb', line 370

def contact_create_process(xml) #:nodoc:
  ret = super
  if (creData = xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:creData', EPPClient::SCHEMAS_URL)).size > 0
	ret[:nhStatus] = creData.xpath('frnic:nhStatus', EPPClient::SCHEMAS_URL).attr('new').value == '1'
	ret[:idStatus] = creData.xpath('frnic:idStatus', EPPClient::SCHEMAS_URL).text
  end
  ret
end

#contact_create_xml(contact) ⇒ Object

:nodoc:



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/epp-client/afnic.rb', line 232

def contact_create_xml(contact) #:nodoc:
  ret = super

  ext = extension do |xml|
	xml.ext( :xmlns => EPPClient::SCHEMAS_URL['frnic']) do
	  xml.create do
 xml.contact do
   if contact.key?(:legalEntityInfos)
		lEI = contact[:legalEntityInfos]
		xml.legalEntityInfos do
xml.idStatus(lEI[:idStatus]) if lEI.key?(:idStatus)
xml.legalStatus(:s => lEI[:legalStatus])
[:siren, :VAT, :trademark, :DUNS, :local].each do |val|
  if lEI.key?(val)
    xml.__send__(val, lEI[val])
  end
end
if lEI.key?(:asso)
  asso = lEI[:asso]
  xml.asso do
    if asso.key?(:waldec)
			xml.waldec(asso[:waldec])
    else
			xml.decl(asso[:decl]) if asso.key?(:decl)
			attrs = {:page => asso[:publ][:page]}
			attrs[:announce] = asso[:publ][:announce] if asso[:publ].key?(:announce)
			xml.publ(attrs, asso[:publ][:date])
    end
  end
end
		end
   else
		if contact.key?(:list)
xml.list(contact[:list])
		end
		if contact.key?(:individualInfos)
iI = contact[:individualInfos]
xml.individualInfos do
  xml.idStatus(iI[:idStatus]) if iI.key?(:idStatus)
  xml.birthDate(iI[:birthDate])
  if iI.key?(:birthCity)
    xml.birthCity(iI[:birthCity])
  end
  if iI.key?(:birthPc)
    xml.birthPc(iI[:birthPc])
  end
  xml.birthCc(iI[:birthCc])
end
		end
		if contact.key?(:firstName)
xml.firstName(contact[:firstName])
		end
   end
   if contact.key?(:reachable)
		if Hash === (reachable = contact[:reachable])
xml.reachable(reachable, 1)
		else
raise ArgumentError, "reachable has to be a Hash"
		end
   end
 end
	  end
	end
  end

  insert_extension(ret, ext)
end

#contact_delete(args) ⇒ Object

Raises an exception, as contacts are deleted with a garbage collector.

Raises:

  • (NotImplementedError)


389
390
391
# File 'lib/epp-client/afnic.rb', line 389

def contact_delete(args)
  raise NotImplementedError, "Contacts are deleted with a garbage collector"
end

#contact_info(contact) ⇒ Object

Extends the EPPClient::Contact#contact_info so that the specific AFNIC check informations are processed, the additionnal informations are :

either :

:legalEntityInfos

indicating that the contact is an organisation with the following informations :

:legalStatus

should be either company, association or other.

:idStatus

indicates the identification process status. Has optional :when and :source attributes.

:siren

contains the SIREN number of the organisation.

:VAT

is optional and contains the VAT number of the organisation.

:trademark

is optional and contains the trademark number of the organisation.

:DUNS

is optional and contains the Data Universal Numbering System number of the organisation.

:local

is optional and contains an identifier local to the eligible country.

:asso

indicates the organisation is an association and contains either a waldec or a decl and a publ :

:waldec

contains the waldec id of the association.

:decl

optionally indicate the date of the association was declared at the prefecture.

:publ

contains informations regarding the publication in the “Journal Officiel” :

:date

the date of publication.

:page

the page the announce is on.

:announce

the announce number on the page (optional).

:individualInfos

indicating that the contact is a person with the following informations :

:idStatus

indicates the identification process status. Has optional :when and :source attributes.

:birthDate

the date of birth of the contact.

:birthCity

the city of birth of the contact.

:birthPc

the postal code of the city of birth.

:birthCc

the country code of the place of birth.

Additionnaly, when the contact is a person, there can be the following informations :

:firstName

the first name of the person. (The last name being stored in the name field in the postalInfo.)

:list

with the value of restrictedPublication mean that the element diffusion should be restricted.

Optionnaly, there can be :

:obsoleted

the contact info is obsolete since/from the optional date :when.

:reachable

the contact is reachable through the optional :media since/from the optional date :when. The info having been specified by the :source.



176
177
178
# File 'lib/epp-client/afnic.rb', line 176

def contact_info(contact)
  super # placeholder so that I can add some doc
end

#contact_info_process(xml) ⇒ Object

:nodoc:



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/epp-client/afnic.rb', line 180

def contact_info_process(xml) #:nodoc:
  ret = super
  if (contact = xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:infData/frnic:contact', EPPClient::SCHEMAS_URL)).size > 0
	if (list = contact.xpath('frnic:list', EPPClient::SCHEMAS_URL)).size > 0
	  ret[:list] = list.map {|l| l.text}
	end
	if (firstName = contact.xpath('frnic:firstName', EPPClient::SCHEMAS_URL)).size > 0
	  ret[:firstName] = firstName.text
	end
	if (iI = contact.xpath('frnic:individualInfos', EPPClient::SCHEMAS_URL)).size > 0
	  ret[:individualInfos] = {}
	  ret[:individualInfos][:birthDate] = Date.parse(iI.xpath('frnic:birthDate', EPPClient::SCHEMAS_URL).text)
	  if (r = iI.xpath("frnic:idStatus", EPPClient::SCHEMAS_URL)).size > 0
 ret[:individualInfos][:idStatus] = {:value => r.text}
 ret[:individualInfos][:idStatus][:when] = r.attr('when').value if r.attr('when')
 ret[:individualInfos][:idStatus][:source] = r.attr('source').value if r.attr('source')
	  end
	  %w(birthCity birthPc birthCc).each do |val|
 if (r = iI.xpath("frnic:#{val}", EPPClient::SCHEMAS_URL)).size > 0
   ret[:individualInfos][val.to_sym] = r.text
 end
	  end
	end
	if (leI = contact.xpath('frnic:legalEntityInfos', EPPClient::SCHEMAS_URL)).size > 0
	  ret[:legalEntityInfos] = legalEntityInfos(leI)
	end
	if (obsoleted = contact.xpath('frnic:obsoleted', EPPClient::SCHEMAS_URL)).size > 0
	  if obsoleted.text != '0'
 ret[:obsoleted] = {}
 if v_when = obsoleted.attr('when')
   ret[:obsoleted][:when] = DateTime.parse(v_when.value)
 end
	  end
	end
	if (reachable = contact.xpath('frnic:reachable', EPPClient::SCHEMAS_URL)).size > 0
	  if reachable.text != '0'
 ret[:reachable] = {}
 if v_when = reachable.attr('when')
   ret[:reachable][:when] = DateTime.parse(v_when.value)
 end
 if media = reachable.attr('media')
   ret[:reachable][:media] = media.value
 end
 if source = reachable.attr('source')
   ret[:reachable][:source] = source.value
 end
	  end
	end
  end
  ret
end

#contact_update(args) ⇒ Object

Extends the EPPClient::Contact#contact_update so that the specific AFNIC update informations can be sent, the additionnal informations are :

:add/:rem

adds or removes the following datas :

:list

with the value of restrictedPublication mean that the element diffusion should/should not be restricted.

:idStatus

indicates the identification process status.

:reachable

the contact is reachable through the optional :media.



443
444
445
# File 'lib/epp-client/afnic.rb', line 443

def contact_update(args)
  super # placeholder so that I can add some doc
end

#contact_update_xml(args) ⇒ Object

:nodoc:



393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/epp-client/afnic.rb', line 393

def contact_update_xml(args) #:nodoc:
  ret = super

  if [:add, :rem].any? {|c| args.key?(c) && [:list, :reachable, :idStatus].any? {|k| args[c].key?(k)}}
	ext = extension do |xml|
	  xml.ext( :xmlns => EPPClient::SCHEMAS_URL['frnic']) do
 xml.update do
   xml.contact do
		[:add, :rem].each do |c|
if args.key?(c) && [:list, :reachable, :idStatus].any? {|k| args[c].key?(k)}
  xml.__send__(c) do
    if args[c].key?(:list)
			xml.list(args[c][:list])
    end
    if args[c].key?(:idStatus)
			xml.idStatus(args[c][:idStatus])
    end
    if args[c].key?(:reachable)
			if Hash === (reachable = args[c][:reachable])
 xml.reachable(reachable, 1)
			else
 raise ArgumentError, "reachable has to be a Hash"
			end
    end
  end
end
		end
   end
 end
	  end
	end

	return insert_extension(ret, ext)
  else
	return ret
  end
end

#domain_afnic_trade_response(xml) ⇒ Object

:nodoc:



504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
# File 'lib/epp-client/afnic.rb', line 504

def domain_afnic_trade_response(xml) #:nodoc:
  dom = xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:trdData/frnic:domain', EPPClient::SCHEMAS_URL)
  ret = {
	:name     => dom.xpath('frnic:name', EPPClient::SCHEMAS_URL).text,
	:trStatus => dom.xpath('frnic:trStatus', EPPClient::SCHEMAS_URL).text,
	:reID     => dom.xpath('frnic:reID', EPPClient::SCHEMAS_URL).text,
	:reDate   => DateTime.parse(dom.xpath('frnic:reDate', EPPClient::SCHEMAS_URL).text),
	:acID     => dom.xpath('frnic:acID', EPPClient::SCHEMAS_URL).text,
  }

  # FIXME: there are discrepencies between the 1.2 xmlschema, the documentation and the reality, I'm trying to stick to reality here.
  %w(reHldID acHldID).each do |f|
	if (field = dom.xpath("frnic:#{f}", EPPClient::SCHEMAS_URL)).size > 0
	  ret[f.to_sym] = field.text
	end
  end
  %w(rhDate ahDate).each do |f|
	if (field = dom.xpath("frnic:#{f}", EPPClient::SCHEMAS_URL)).size > 0
	  ret[f.to_sym] = DateTime.parse(field.text)
	end
  end
  ret
end

#domain_check(*domains) ⇒ Object

Extends the EPPClient::Domain#domain_check so that the specific AFNIC check informations are processed, the additionnal informations are :

:reserved

the domain is a reserved name.

:rsvReason

the optional reason why the domain is reserved.

:forbidden

the domain is a forbidden name.

:fbdReason

the optional reason why the domain is forbidden.



42
43
44
# File 'lib/epp-client/afnic.rb', line 42

def domain_check(*domains)
  super # placeholder so that I can add some doc
end

#domain_check_process(xml) ⇒ Object

:nodoc:



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/epp-client/afnic.rb', line 46

def domain_check_process(xml) # :nodoc:
  ret = super
  xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:chkData/frnic:domain/frnic:cd', EPPClient::SCHEMAS_URL).each do |dom|
	name = dom.xpath('frnic:name', EPPClient::SCHEMAS_URL)
	hash = ret.select {|d| d[:name] == name.text}.first
	hash[:reserved] = name.attr('reserved').value == "1"
	unless (reason = dom.xpath('frnic:rsvReason', EPPClient::SCHEMAS_URL).text).empty?
	  hash[:rsvReason] = reason
	end
	hash[:forbidden] = name.attr('forbidden').value == "1"
	unless (reason = dom.xpath('frnic:fbdReason', EPPClient::SCHEMAS_URL).text).empty?
	  hash[:fbdReason] = reason
	end
  end
  return ret
end

#domain_create(args) ⇒ Object

Extends the EPPClient::Domain#domain_create to make sure there’s no :ns, :dsData or :keyData records, AFNIC’s servers sends quite a strange error when there is.

Raises:

  • (ArgumentError)


382
383
384
385
386
# File 'lib/epp-client/afnic.rb', line 382

def domain_create(args)
  raise ArgumentError, "You can't create a domain with ns records, you must do an update afterwards" if args.key?(:ns)
  raise ArgumentError, "You can't create a domain with ds or key records, you must do an update afterwards" if args.key?(:dsData) || args.key?(:keyData)
  super
end

#domain_info(domain) ⇒ Object

Extends the EPPClient::Domain#domain_info so that the specific AFNIC :status can be added.



65
66
67
# File 'lib/epp-client/afnic.rb', line 65

def domain_info(domain)
  super # placeholder so that I can add some doc
end

#domain_info_process(xml) ⇒ Object

:nodoc:



69
70
71
72
73
74
75
76
# File 'lib/epp-client/afnic.rb', line 69

def domain_info_process(xml) #:nodoc:
  ret = super
  if (frnic_status = xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:infData/frnic:domain/frnic:status', EPPClient::SCHEMAS_URL)).size > 0
	ret[:status] ||= [] # The status is optional, there may be none at this point.
	ret[:status] += frnic_status.map {|s| s.attr('s')}
  end
  ret
end

#domain_update(args) ⇒ Object

Extends the EPPClient::Domain#domain_update so that AFNIC’s weirdnesses can be taken into account.

AFNIC does not support ns/hostObj, only ns/hostAttr/Host*, so, take care of this here. Also, you can only do one of the following at a time :

  • update contacts

  • update name servers

  • update status & authInfo



456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
# File 'lib/epp-client/afnic.rb', line 456

def domain_update(args)
  if args.key?(:chg) && args[:chg].key?(:registrant)
	raise ArgumentError, "You need to do a trade or recover operation to change the registrant"
  end
  has_contacts = args.key?(:add) && args[:add].key?(:contacts) || args.key?(:add) && args[:add].key?(:contacts)
  has_ns = args.key?(:add) && args[:add].key?(:ns) || args.key?(:add) && args[:add].key?(:ns)
  has_other = args.key?(:add) && args[:add].key?(:status) || args.key?(:add) && args[:add].key?(:status) || args.key?(:chg) && args[:chg].key?(:authInfo)
  if [has_contacts, has_ns, has_other].select {|v| v}.size > 1
	raise ArgumentError, "You can't update all that at one time"
  end
  [:add, :rem].each do |ar|
	if args.key?(ar) && args[ar].key?(:ns) && String === args[ar][:ns].first
	  args[ar][:ns] = args[ar][:ns].map {|ns| {:hostName => ns}}
	end
  end
  super
end

#poll_reqObject

Extends the EPPClient::Poll#poll_req to be able to parse quallification response extension.



476
477
478
# File 'lib/epp-client/afnic.rb', line 476

def poll_req
  super # placeholder so that I can add some doc
end