Class: KonoEppClient::Server

Inherits:
Object
  • Object
show all
Includes:
RequiresParameters, REXML
Defined in:
lib/kono_epp_client/server.rb

Constant Summary collapse

DNS_CHECK_NS_SET =

Se la risposta al login contiene questo tipo di chiave-valore, allora la comunicazione può avvenire con comandi aggiuntivi DNSSEC

Set.new([["xmlns:secDNS", "urn:ietf:params:xml:ns:secDNS-1.1"],
                            ["xmlns:extsecDNS", "http://www.nic.it/ITNIC-EPP/extsecDNS-1.0"]],
)

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from RequiresParameters

#requires!

Constructor Details

#initialize(attributes = {}) ⇒ Server

Required Attrbiutes

  • :server - The EPP server to connect to

  • :tag - The tag or username used with <login> requests.

  • :password - The password used with <login> requests.

Optional Attributes

  • :port - The EPP standard port is 700. However, you can choose a different port to use.

  • :clTRID - The client transaction identifier is an element that EPP specifies MAY be used to uniquely identify the command to the server. You are responsible for maintaining your own transaction identifier space to ensure uniqueness. Defaults to “ABC-12345”

  • :lang - Set custom language attribute. Default is ‘en’.

  • :services - Use custom EPP services in the <login> frame. The defaults use the EPP standard domain, contact and host 1.0 services.

  • :extensions - URLs to custom extensions to standard EPP. Use these to extend the standard EPP (e.g., Nominet uses extensions). Defaults to none.

  • :version - Set the EPP version. Defaults to “1.0”.

  • :transport - Type of connection (http). Default to “html”

  • :transport_options - Overrides for transport configurations. Default to {}

  • :timeout - Timeout for connections in seconds. Default to “30”

  • :ssl_version - Version of the ssl protocol versione. Default to TLSv1

  • :ssl_version - Version of the ssl protocol versione. Default to TLSv1

  • :enable_dns_sec - Try to enable DNSSEC, the response from login command will say it. default false



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/kono_epp_client/server.rb', line 43

def initialize(attributes = {})
  requires!(attributes, :tag, :password, :server)

  @tag = attributes[:tag]
  @password = attributes[:password]
  @server = attributes[:server]
  @port = attributes[:port] || 700
  @lang = attributes[:lang] || "en"
  @services = attributes[:services] || ["urn:ietf:params:xml:ns:domain-1.0", "urn:ietf:params:xml:ns:contact-1.0", "urn:ietf:params:xml:ns:host-1.0"]
  @extensions = attributes[:extensions] || []
  @version = attributes[:version] || "1.0"
  @transport = attributes[:transport] || :http
  @transport_options = attributes[:transport_options] || {}
  @timeout = attributes[:timeout] || 30
  @ssl_version = attributes[:ssl_version] || :TLSv1

  if attributes[:enable_dns_sec]
    @extensions << "urn:ietf:params:xml:ns:secDNS-1.1"
    @extensions << "http://www.nic.it/ITNIC-EPP/extsecDNS-1.0"
  end

  @logged_in = false
  @dns_sec_enabled = false
end

Instance Attribute Details

#creditObject

Returns the value of attribute credit.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def credit
  @credit
end

#dns_sec_enabledObject (readonly) Also known as: dns_sec_enabled?

Returns the value of attribute dns_sec_enabled.



19
20
21
# File 'lib/kono_epp_client/server.rb', line 19

def dns_sec_enabled
  @dns_sec_enabled
end

#extensionsObject

Returns the value of attribute extensions.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def extensions
  @extensions
end

#langObject

Returns the value of attribute lang.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def lang
  @lang
end

#old_serverObject

Returns the value of attribute old_server.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def old_server
  @old_server
end

#passwordObject

Returns the value of attribute password.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def password
  @password
end

#portObject

Returns the value of attribute port.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def port
  @port
end

#serverObject

Returns the value of attribute server.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def server
  @server
end

#servicesObject

Returns the value of attribute services.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def services
  @services
end

#ssl_versionObject

Returns the value of attribute ssl_version.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def ssl_version
  @ssl_version
end

#tagObject

Returns the value of attribute tag.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def tag
  @tag
end

#timeoutObject

Returns the value of attribute timeout.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def timeout
  @timeout
end

#transportObject

Returns the value of attribute transport.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def transport
  @transport
end

#transport_optionsObject

Returns the value of attribute transport_options.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def transport_options
  @transport_options
end

#versionObject

Returns the value of attribute version.



15
16
17
# File 'lib/kono_epp_client/server.rb', line 15

def version
  @version
end

Instance Method Details

#change_password(new_password) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/kono_epp_client/server.rb', line 100

def change_password(new_password)
   = Commands::Login.new(tag, password)

  # FIXME: Order matters
  .new_password = new_password

  .version = version
  .lang = lang

  .services = services
  .extensions = extensions

  send_command()
end

#check_contacts(ids) ⇒ Object



143
144
145
# File 'lib/kono_epp_client/server.rb', line 143

def check_contacts(ids)
  send_command(Commands::CheckContacts.new(ids))
end

#check_domains(*domains) ⇒ Object



166
167
168
# File 'lib/kono_epp_client/server.rb', line 166

def check_domains(*domains)
  send_command(Commands::CheckDomains.new *domains)
end

#close_connectionObject

Closes the connection to the EPP server.



75
76
77
# File 'lib/kono_epp_client/server.rb', line 75

def close_connection
  @connection.close
end

#connect_and_helloObject



68
69
70
71
72
# File 'lib/kono_epp_client/server.rb', line 68

def connect_and_hello
  open_connection

  hello
end

#create_contact(options) ⇒ Object



138
139
140
141
# File 'lib/kono_epp_client/server.rb', line 138

def create_contact(options)
  contact = Commands::CreateContact.new options
  send_command(contact)
end

#create_domain(options) ⇒ Object



157
158
159
160
161
162
163
164
# File 'lib/kono_epp_client/server.rb', line 157

def create_domain(options)
  dns_sec_data = options.delete(:dns_sec_data)||[]
  if dns_sec_enabled?
    options[:dns_sec_data] = dns_sec_data
  end
  domain = Commands::CreateDomain.new options
  send_command(domain)
end

#delete_contact(id) ⇒ Object



147
148
149
150
# File 'lib/kono_epp_client/server.rb', line 147

def delete_contact(id)
  contact = Commands::DeleteContact.new id
  send_command(contact)
end

#delete_domain(name) ⇒ Object



179
180
181
182
# File 'lib/kono_epp_client/server.rb', line 179

def delete_domain(name)
  domain = Commands::DeleteDomain.new name
  send_command(domain)
end

#helloObject

FIXME: Remove command wrappers?



126
127
128
# File 'lib/kono_epp_client/server.rb', line 126

def hello
  send_request(Commands::Hello.new.to_s)
end

#info_contact(id) ⇒ Object



184
185
186
187
# File 'lib/kono_epp_client/server.rb', line 184

def info_contact(id)
  contact = Commands::InfoContact.new id
  send_command(contact)
end

#info_domain(name) ⇒ Object



189
190
191
192
# File 'lib/kono_epp_client/server.rb', line 189

def info_domain(name)
  info = Commands::InfoDomain.new name
  send_command(info)
end

#logged_in?Boolean

Returns:

  • (Boolean)


115
116
117
118
119
120
121
122
123
# File 'lib/kono_epp_client/server.rb', line 115

def logged_in?
  begin
    poll
  rescue
    return false
  end

  return true
end

#loginObject

Sends a standard login request to the EPP server.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/kono_epp_client/server.rb', line 80

def 
   = Commands::Login.new(tag, password)

  # FIXME: Order matters
  .version = version
  .lang = lang

  .services = services
  .extensions = extensions

  response = send_command()

  response_set = Set.new(response.namespaces.to_a)
  if response_set.superset?(DNS_CHECK_NS_SET)
    @dns_sec_enabled = true
  end

  response
end

#logoutObject

Sends a standard logout request to the EPP server.



199
200
201
# File 'lib/kono_epp_client/server.rb', line 199

def logout
  send_command(Commands::Logout.new, 1500)
end

#open_connectionObject

Establishes the connection to the server. If the connection is established, then this method will call read and return the EPP <greeting> which is sent by the server upon connection.



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/kono_epp_client/server.rb', line 273

def open_connection
  # FIXME il timeout serve solamente nella versione tcp
  # FIXME perchè utilizzare un'istanza di classe? non sarebbe meglio avere un metodo che genera il transport
  #       e successivamente viene utilizzato sempre quello?
  Timeout.timeout @timeout do
    case @transport
    when :http

      options = {
        ssl_version: ssl_version,
        cookie_file: "#{@tag.downcase}.cookies.pstore"
      }.merge(@transport_options)

      @connection = KonoEppClient::Transport::HttpTransport.new(server, port, **options)
    else
      raise "Not Implemented #{@transport}"
    end
  end
end

#poll(id = nil) ⇒ Object



130
131
132
133
134
135
136
# File 'lib/kono_epp_client/server.rb', line 130

def poll(id = nil)
  poll = Commands::Poll.new(id ? :ack : :req)

  poll.ack_id = id if id

  send_command(poll)
end

#readObject

Receive an EPP response from the server. Since the connection is blocking, this method will wait until the connection becomes available for use. If the connection is broken, a SocketError will be raised. Otherwise, it will return a string containing the XML from the server.



297
298
299
300
301
# File 'lib/kono_epp_client/server.rb', line 297

def read
  Timeout.timeout @timeout do
    @connection.read
  end
end

#send_command(command, expected_result = 1000..1999) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
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
# File 'lib/kono_epp_client/server.rb', line 211

def send_command(command, expected_result = 1000..1999)
  namespaces = {'extepp' => 'http://www.nic.it/ITNIC-EPP/extepp-2.0',
                'xmlns' => "urn:ietf:params:xml:ns:epp-1.0"}

  xml = Nokogiri.XML(send_request(command.to_s))

  # TODO: multiple <response> RFC 3730 §2.6
  result = xml.at_xpath("/xmlns:epp/xmlns:response[1]/xmlns:result",
                        namespaces)
  raise Exceptions::ErrorResponse.new(:message => 'Malformed response') if result.nil?

  xmlns_code = result.at_xpath("@code")
  raise Exceptions::ErrorResponse.new(:message => 'Malformed response') if xmlns_code.nil?

  response_code = xmlns_code.value.to_i

  xmlns_msg = result.xpath("xmlns:msg/text ()",
                           namespaces)
  raise Exceptions::ErrorResponse.new(:message => 'Malformed response') if xmlns_msg.empty?

  result_message = xmlns_msg.text.strip

  # TODO: value

  xmlns_ext_reason = result.xpath("xmlns:extValue/xmlns:reason",
                                  namespaces)
  result_message += ": #{xmlns_ext_reason.text.strip}" unless xmlns_ext_reason.empty?

  xmlns_reason_code = result.xpath("xmlns:extValue/xmlns:value/extepp:reasonCode",
                                   namespaces)
  reason_code = xmlns_reason_code.text.strip.to_i unless xmlns_reason_code.empty?

  credit_msg = xml.xpath("//extepp:credit/text ()", namespaces)
  @credit = credit_msg.text.to_f unless credit_msg.empty?

  if expected_result === response_code
    return xml
  end

  args = {:xml => xml,
          :response_code => response_code,
          :reason_code => reason_code,
          :message => result_message}

  case [response_code, reason_code]
  when [2200, 6004]
    raise Exceptions::AuthenticationPasswordExpired.new(args)
  when [2002, 4015]
    raise Exceptions::LoginNeeded.new(args)
  when [2304, 9022]
    raise Exceptions::DomainHasStatusCliTransProhibited.new(args)
  when [2304, 9026]
    raise Exceptions::DomainHasStatusClientUpdateProhibited.new(args)
  else
    raise Exceptions::ErrorResponse.new(args)
  end
end

#send_request(xml) ⇒ Object

private Wrapper which sends XML to the server, and receives the response in return.



206
207
208
209
# File 'lib/kono_epp_client/server.rb', line 206

def send_request(xml)
  write(xml)
  read
end

#transfer_domain(name, authinfo, op, extension: nil) ⇒ Object



194
195
196
# File 'lib/kono_epp_client/server.rb', line 194

def transfer_domain(name, authinfo, op, extension: nil)
  send_command(Commands::TransferDomain.new(name, authinfo, op, extension: extension))
end

#update_contact(options) ⇒ Object



152
153
154
155
# File 'lib/kono_epp_client/server.rb', line 152

def update_contact(options)
  contact = Commands::UpdateContact.new options
  send_command(contact)
end

#update_domain(options) ⇒ Object



170
171
172
173
174
175
176
177
# File 'lib/kono_epp_client/server.rb', line 170

def update_domain(options)
  dns_sec_data = options.delete(:dns_sec_data)||[]
  if dns_sec_enabled?
    options[:dns_sec_data] = dns_sec_data
  end
  domain = Commands::UpdateDomain.new options
  send_command(domain)
end

#write(xml) ⇒ Object

Send XML to the server. If the socket returns EOF, the connection has closed and a SocketError is raised.



305
306
307
308
309
# File 'lib/kono_epp_client/server.rb', line 305

def write(xml)
  Timeout.timeout @timeout do
    @connection.write(xml)
  end
end