File Coverage

blib/lib/IO/EPP/Flexireg.pm
Criterion Covered Total %
statement 12 126 9.5
branch 0 48 0.0
condition 0 25 0.0
subroutine 4 14 28.5
pod 9 10 90.0
total 25 223 11.2


line stmt bran cond sub pod time code
1             package IO::EPP::Flexireg;
2              
3             =encoding utf8
4              
5             =head1 NAME
6              
7             IO::EPP::Flexireg
8              
9             =head1 SYNOPSIS
10              
11             use IO::EPP::Flexireg;
12              
13             # Parameters for IO::Socket::SSL
14             my %sock_params = (
15             PeerHost => 'epp.flexireg.net',
16             PeerPort => 700,
17             Timeout => 30,
18             );
19              
20             # Create object, get greeting and call login()
21             my $conn = IO::EPP::Flexireg->new( {
22             user => 'login-msk-fir',
23             pass => 'xxxxxxxx',
24             sock_params => \%sock_params,
25             test_mode => 0, # real connect
26             } );
27              
28             # Check domain
29             my ( $answ, $code, $msg ) = $conn->check_domains( { domains => [ 'my.moscow', 'xn--l1ae5c.xn--80adxhks' ] } );
30              
31             # Call logout() and destroy object
32             undef $conn;
33              
34             =head1 DESCRIPTION
35              
36             Module work with Flexireg tlds: .moscow, .москва, ru.net and 3lvl.ru/su
37              
38             Frontend:
39             https://faitid.org/
40              
41             Backend:
42             http://flexireg.net/
43              
44              
45             Documentaion:
46              
47             moscow, москва
48             L,
49             L,
50             L
51              
52             ru.net+
53             L,
54             L
55              
56              
57             =cut
58              
59 1     1   2357 use IO::EPP::Base;
  1         3  
  1         45  
60 1     1   7 use parent qw( IO::EPP::Base );
  1         2  
  1         7  
61              
62 1     1   70 use strict;
  1         2  
  1         21  
63 1     1   5 use warnings;
  1         1  
  1         1771  
64              
65             my $cont_ext =
66             'xmlns:contact="http://www.tcinet.ru/epp/tci-contact-ext-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.tcinet.ru/epp/tci-contact-ext-1.0 tci-contact-ext-1.0.xsd"';
67             my $rgp_ext =
68             'xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:rgp-1.0 rgp-1.0.xsd"';
69              
70             sub make_request {
71 0     0 1   my ( $action, $params ) = @_;
72              
73 0           my ( $self, $code, $msg, $answ );
74              
75 0 0         unless ( $params->{conn} ) {
76 0   0       $params->{sock_params}{PeerHost} ||= 'epp.flexireg.net';
77 0   0       $params->{sock_params}{PeerPort} ||= 700;
78              
79 0           ( $self, $code, $msg ) = __PACKAGE__->new( $params );
80              
81 0 0 0       unless ( $code and $code == 1000 ) {
82 0           goto END_MR;
83             }
84             }
85             else {
86 0           $self = $params->{conn};
87             }
88              
89              
90 0           $self->{critical_error} = '';
91              
92 0 0         if ( $self->can( $action ) ) {
93 0           ( $answ, $code, $msg ) = $self->$action( $params );
94             }
95             else {
96 0           $msg = "undefined command <$action>, request cancelled";
97 0           $code = 0;
98             }
99              
100              
101             END_MR:
102              
103 0 0         $msg .= '; ' . $self->{critical_error} if $self->{critical_error};
104              
105 0           my $full_answ = "code: $code\nmsg: $msg";
106              
107 0 0 0       $answ = {} unless $answ && ref $answ;
108              
109 0           $answ->{code} = $code;
110 0           $answ->{msg} = $msg;
111              
112 0 0         return wantarray ? ( $answ, $full_answ, $self ) : $answ;
113             }
114              
115             =head1 METHODS
116              
117             Further overlap functions where the provider has features
118              
119             =head2 login
120              
121             Ext params for login,
122              
123             INPUT: new password for change
124              
125             =cut
126              
127             sub login {
128 0     0 1   my ( $self, $pw ) = @_;
129              
130 0           my $svcs = '
131             urn:ietf:params:xml:ns:contact-1.0
132             urn:ietf:params:xml:ns:domain-1.0
133             urn:ietf:params:xml:ns:host-1.0';
134 0           my $extension = '
135             http://www.tcinet.ru/epp/tci-contact-ext-1.0
136             urn:ietf:params:xml:ns:fee-0.11
137             urn:ietf:params:xml:ns:idn-1.0
138             urn:ietf:params:xml:ns:launch-1.0
139             urn:ietf:params:xml:ns:rgp-1.0
140             urn:ietf:params:xml:ns:secDNS-1.1';
141              
142 0           return $self->SUPER::login( $pw, $svcs, $extension );
143             }
144              
145             sub contact_ext {
146 0     0 0   my ( undef, $params ) = @_;
147              
148 0           my $ext = '';
149              
150 0 0         if ( $params->{birthday} ) {
151 0           $ext .= "\n";
152              
153 0           foreach my $f ( 'birthday', 'passport', 'TIN' ) {
154 0 0         $ext .= " $$params{$f}\n" if $$params{$f};
155             }
156              
157 0           $ext .= " ";
158             }
159              
160 0 0         if ( $params->{legal} ) {
161 0           $ext .= " \n";
162 0           foreach my $type ( 'int', 'loc' ) {
163 0           $ext .= qq| \n|;
164              
165 0 0         $$params{legal}{$type}{addr} = [ $$params{legal}{$type}{addr} ] unless ref $$params{legal}{$type}{addr};
166              
167 0           foreach my $s ( @{$$params{legal}{$type}{addr}} ) {
  0            
168 0           $ext .= " $s\n";
169             }
170              
171 0           $ext .= " $$params{legal}{$type}{city}\n";
172 0 0         $ext .= ( $$params{legal}{$type}{'state'} ? " $$params{legal}{$type}{state}\n" : " \n" );
173 0 0         $ext .= ( $$params{legal}{$type}{postcode} ? " $$params{legal}{$type}{postcode}\n" : " \n" );
174 0           $ext .= " $$params{legal}{$type}{country_code}\n";
175              
176 0           $ext .= " \n";
177             }
178 0           $ext .= " $$params{TIN}\n";
179 0           $ext .= " ";
180             }
181              
182 0           return $ext;
183             }
184              
185              
186             =head2 create_contact
187              
188             For moscow/москва:
189              
190             When registering a contact, you must specify both int type data and loc type data, and if the domain owner has passport data in Cyrillic,
191             then loc type data must be entered in Cyrillic.
192             This is mandatory for citizens and legal entities of Russia, Ukraine, Belarus and other countries that have the Cyrillic alphabet.
193              
194             In addition, the owner must provide additional information.
195              
196             For individuals:
197              
198             C -- date of birth;
199              
200             C -- passport series and number, by whom and when it was issued;
201              
202             C -- TIN for individual entrepreneurs.
203              
204             For legal entities:
205              
206             hashref C, that contains the legal address, it also needs to specify two types: C and C, consisting of the fields C, C, C, C, C.
207              
208             You also need to specify the C field.
209              
210             An Example:
211              
212             Individuals:
213              
214             my %cont = (
215             int => {
216             first_name => 'Igor',
217             patronymic => 'Igorevich',
218             last_name => 'Igorev',
219             org => '',
220             addr => 'Igoreva str, 129',
221             city => 'Igorevsk',
222             state => 'Ogorevskaya obl.',
223             postcode => '699001',
224             country_code => 'RU',
225             },
226             loc => {
227             first_name => 'Игорь',
228             patronymic => 'Игоревич',
229             last_name => 'Игорев',
230             org => '',
231             addr => 'ул. Игорева, 129',
232             city => 'Игоревск',
233             state => 'Игоревская обл.',
234             postcode => '699001',
235             country_code => 'RU',
236             },
237             birthday => '1909-01-14',
238             passport => '11.11.2011, выдан Отделом УФМС России по Игоревской области в г.Игоревске, 2211 446622',
239             phone => '+7.9012345678',
240             fax => '',
241             email => 'igor@i.ru',
242             TIN => '',
243             };
244              
245             my ( $answ, $msg, $conn ) = make_request( 'create_contact', \%cont );
246              
247             Legal entities:
248              
249             my %cont = (
250             int => {
251             first_name => 'Igor',
252             patronymic => 'Igorevich',
253             last_name => 'Igorev',
254             org => 'Igor and Co',
255             addr => 'Igoreva str, 129',
256             city => 'Igorevsk',
257             state => 'Igorevskaya obl.',
258             postcode => '699001',
259             country_code => 'RU',
260             },
261             loc => {
262             first_name => 'Игорь',
263             patronymic => 'Игоревич',
264             last_name => 'Игорев',
265             org => 'Игорь и Ко',
266             addr => 'ул. Игорева, 129',
267             city => 'Игоревск',
268             state => 'Игоревская обл.',
269             postcode => '699001',
270             country_code => 'RU',
271             },
272             legal => {
273             int => {
274             addr => 'Company str, 1',
275             city => 'Igorevsk',
276             state => 'Igorevskaya obl.',
277             postcode => '699002',
278             country_code => 'RU',
279             },
280             loc => {
281             addr => 'ул. Компаний, 1',
282             city => 'Игоревск',
283             state => 'Игоревская обл.',
284             postcode => '699002',
285             country_code => 'RU',
286             }
287             }
288             };
289              
290             my ( $answ, $code, $msg ) = $conn->create_contact( \%cont );
291              
292             =cut
293              
294             sub create_contact {
295 0     0 1   my ( $self, $params ) = @_;
296              
297 0           $params->{cont_id} = IO::EPP::Base::gen_id( 16 );
298              
299 0           $params->{authinfo} = IO::EPP::Base::gen_pw( 16 );
300              
301 0           my $extension = $self->contact_ext( $params );
302              
303 0 0         if ( $extension ) {
304 0           $params->{extension} = " \n$extension \n";
305             }
306              
307 0           return $self->SUPER::create_contact( $params );
308             }
309              
310              
311             sub get_contact_ext {
312 0     0 1   my ( undef, $ext ) = @_;
313              
314 0           my %cont;
315              
316 0 0         if ( $ext =~ m|]+tci-contact-ext-1[^<>]+>(.+?)|s ) {
317 0           my $data = $1;
318              
319 0 0         if ( $data =~ m|(.+)|s ) {
320 0           my $person_data = $1;
321              
322 0           my @rows = $person_data =~ m|([^<>]+)|gs;
323              
324 0           foreach my $row ( @rows ) {
325 0 0         if ( $row =~ m|([^<>]+)| ) {
326 0           $cont{$1} = $2;
327             }
328             }
329             }
330              
331 0 0         if ( $data =~ m|(.+)|s ) {
332 0           my $org_data = $1;
333              
334 0           ( $cont{TIN} ) = $org_data =~ /([^<>]+)<\/contact:TIN>/;
335              
336 0           my @atypes = ( 'int', 'loc' );
337 0           foreach my $atype ( @atypes ) {
338 0           my ( $postal ) = $org_data =~ m|(.+?)|s;
339              
340 0 0         next unless $postal;
341              
342 0           $cont{legal}{$atype}{addr} = join(' ', $postal =~ /([^<>]*)<\/contact:street>/ );
343              
344 0           ( $cont{legal}{$atype}{city} ) = $postal =~ /([^<>]*)<\/contact:city>/;
345              
346 0           ( $cont{legal}{$atype}{'state'} ) = $postal =~ /([^<>]*)<\/contact:sp>/;
347              
348 0           ( $cont{legal}{$atype}{postcode} ) = $postal =~ /([^<>]*)<\/contact:pc>/;
349              
350 0           ( $cont{legal}{$atype}{country_code} ) = $postal =~ /([A-Z]+)<\/contact:cc>/;
351             }
352             }
353             }
354              
355 0           return \%cont;
356             }
357              
358             =head2 create_domain
359              
360             Domains ru.net+ tlds have only the registrant, without the administrator and other contacts
361              
362             =cut
363              
364             sub create_domain {
365 0     0 1   my ( $self, $params ) = @_;
366              
367 0   0       $params->{authinfo} ||= IO::EPP::Base::gen_pw( 16 );
368              
369 0           my $extension = '';
370              
371 0 0         if ( $params->{dname} =~ /\.xn--80adxhks$/ ) {
372             # .москва support RU lang only
373 0           $extension .= qq| \n|;
374 0           $extension .= " ru-RU\n";
375 0           $extension .= " \n";
376             }
377              
378 0 0 0       if ( $params->{price} or $params->{fee} ) {
379 0   0       my $price = $params->{price} || $params->{fee};
380             # Russian Ruble only
381 0           $extension .= qq| \n|;
382 0           $extension .= " RUB\n";
383 0           $extension .= " $price\n";
384 0           $extension .= " \n";
385             }
386              
387 0 0         $params->{extension} = $extension if $extension;
388              
389 0           return $self->SUPER::create_domain( $params );
390             }
391              
392              
393             sub get_domain_spec_ext {
394 0     0 1   my ( undef, $ext ) = @_;
395              
396 0           my %info;
397              
398 0 0         if ( $ext =~ /(.+?)<\/idn:data>/s ) {
399 0           my $idn = $1;
400              
401 0           ( $info{uname} ) = $idn =~ /([^<>]+)<\/idn:uname>/;
402             }
403              
404 0           return \%info;
405             }
406              
407              
408             sub renew_domain {
409 0     0 1   my ( $self, $params ) = @_;
410              
411 0           my $extension = '';
412              
413 0 0 0       if ( $params->{price} or $params->{fee} ) {
414 0   0       my $price = $params->{price} || $params->{fee};
415             # Russian Ruble only
416 0           $extension .= qq| \n|;
417 0           $extension .= " RUB\n";
418 0           $extension .= " $price\n";
419 0           $extension .= " \n";
420             }
421              
422 0 0         $params->{extension} = $extension if $extension;
423              
424 0           return $self->SUPER::renew_domain( $params );
425             }
426              
427              
428             =head2 restore_domain
429              
430             first call for restore_domain
431              
432             =cut
433              
434             sub restore_domain {
435 0     0 1   my ( $self, $params ) = @_;
436              
437 0           $params->{extension} = qq|
438            
439             |;
440              
441 0           return $self->SUPER::update_domain( $params );
442             }
443              
444              
445             =head2 confirmations_restore_domain
446              
447             Second call for restore_domain
448              
449             =over 4
450              
451             =item C
452              
453             whois before delete;
454              
455             =item C
456              
457             whois on now;
458              
459             =item C
460              
461             delete domain date-time, see. upd_date in domain:info before call restore_domain;
462              
463             =item C
464              
465             restore request call datetime in UTC;
466              
467             =item C
468              
469             restore reason,
470              
471             variants: C, C, C;
472              
473             =item C
474              
475             need to write what it is for the client;
476              
477             =item C
478              
479             can and without other.
480              
481             =back
482              
483             =cut
484              
485             sub confirmations_restore_domain {
486 0     0 1   my ( $self, $params ) = @_;
487              
488 0           $params->{extension} = <
489            
490            
491            
492             $$params{pre_data}
493             $$params{post_data}
494             $$params{del_time}
495             $$params{rest_time}
496             $$params{reason}
497             $$params{statement}
498            
499            
500            
501            
502             RGPEXT
503              
504 0           return $self->SUPER::update_domain( $params );
505             }
506              
507              
508             1;
509              
510              
511             __END__