File Coverage

blib/lib/IO/EPP/Flexireg.pm
Criterion Covered Total %
statement 12 124 9.6
branch 0 48 0.0
condition 0 25 0.0
subroutine 4 14 28.5
pod 9 10 90.0
total 25 221 11.3


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   2408 use IO::EPP::Base;
  1         3  
  1         42  
60 1     1   7 use parent qw( IO::EPP::Base );
  1         2  
  1         7  
61              
62 1     1   69 use strict;
  1         3  
  1         18  
63 1     1   5 use warnings;
  1         2  
  1         1776  
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             =head2 get_contact_ext
311              
312             Parsing the tcinet extension for get_contact_info:
313              
314             C and C for individuals;
315              
316             C address for legal entities.
317              
318             An Example
319              
320             {
321             'int' => {
322             'city' => 'Kaluga',
323             'country_code' => 'RU',
324             'name' => 'Igor Igorevich Igover',
325             'postcode' => '248000',
326             'addr' => 'Barrikadnaya 1',
327             'state' => 'Kaluzhskaya obl.'
328             },
329             'roid' => '22222217183841759329_aed2a25748687035b9ad8dcbcf839171_contact-FIR',
330             'cre_date' => '2020-01-01 10:10:10',
331             'TIN' => 'FICTION-01',
332             'email' => [
333             'i@go.ru'
334             ],
335             'fax' => [],
336             'legal' => {
337             'int' => {
338             'city' => 'Moscow',
339             'country_code' => 'RU',
340             'postcode' => '123456',
341             'addr' => 'ul. Vasi Petushkova, dom 3',
342             'state' => 'Moscow'
343             },
344             'loc' => {
345             'city' => 'Москва',
346             'country_code' => 'RU',
347             'postcode' => '123456',
348             'addr' => 'Васи Петушкова стриит., хаус 3',
349             'state' => 'Москва'
350             }
351             },
352             'creater' => 'login-msk-fir',
353             'authinfo' => 'khylMUWPjpqU=%9Y',
354             'code' => '1000',
355             'owner' => 'login-msk-fir',
356             'msg' => 'Command completed successfully',
357             'phone' => [
358             '+7.9166337777'
359             ],
360             'cont_id' => 'jsybsvtjjjjj',
361             'loc' => {
362             'city' => 'Калуга',
363             'country_code' => 'RU',
364             'name' => 'Игорь Игоревич Игорев',
365             'postcode' => '248000',
366             'addr' => 'Баррикадная 1',
367             'state' => 'Калужская обл.'
368             },
369             'statuses' => {
370             'ok' => '+'
371             }
372             };
373              
374             =cut
375              
376             sub get_contact_ext {
377 0     0 1   my ( undef, $cont, $ext ) = @_;
378              
379 0 0         if ( $ext =~ m|]+tci-contact-ext-1[^<>]+>(.+?)|s ) {
380 0           my $data = $1;
381              
382 0 0         if ( $data =~ m|(.+)|s ) {
383 0           my $person_data = $1;
384              
385 0           my @rows = $person_data =~ m|([^<>]+)|gs;
386              
387 0           foreach my $row ( @rows ) {
388 0 0         if ( $row =~ m|([^<>]+)| ) {
389 0           $cont->{$1} = $2;
390             }
391             }
392             }
393              
394 0 0         if ( $data =~ m|(.+)|s ) {
395 0           my $org_data = $1;
396              
397 0           ( $cont->{TIN} ) = $org_data =~ /([^<>]+)<\/contact:TIN>/;
398              
399 0           my @atypes = ( 'int', 'loc' );
400 0           foreach my $atype ( @atypes ) {
401 0           my ( $postal ) = $org_data =~ m|(.+?)|s;
402              
403 0 0         next unless $postal;
404              
405 0           $cont->{legal}{$atype}{addr} = join(' ', $postal =~ /([^<>]*)<\/contact:street>/ );
406              
407 0           ( $cont->{legal}{$atype}{city} ) = $postal =~ /([^<>]*)<\/contact:city>/;
408              
409 0           ( $cont->{legal}{$atype}{'state'} ) = $postal =~ /([^<>]*)<\/contact:sp>/;
410              
411 0           ( $cont->{legal}{$atype}{postcode} ) = $postal =~ /([^<>]*)<\/contact:pc>/;
412              
413 0           ( $cont->{legal}{$atype}{country_code} ) = $postal =~ /([A-Z]+)<\/contact:cc>/;
414             }
415             }
416             }
417             }
418              
419             =head2 create_domain
420              
421             Domains ru.net+ tlds have only the registrant, without the administrator and other contacts
422              
423             =cut
424              
425             sub create_domain {
426 0     0 1   my ( $self, $params ) = @_;
427              
428 0   0       $params->{authinfo} ||= IO::EPP::Base::gen_pw( 16 );
429              
430 0           my $extension = '';
431              
432 0 0         if ( $params->{dname} =~ /\.xn--80adxhks$/ ) {
433             # .москва support RU lang only
434 0           $extension .= qq| \n|;
435 0           $extension .= " ru-RU\n";
436 0           $extension .= " \n";
437             }
438              
439 0 0 0       if ( $params->{price} or $params->{fee} ) {
440 0   0       my $price = $params->{price} || $params->{fee};
441             # Russian Ruble only
442 0           $extension .= qq| \n|;
443 0           $extension .= " RUB\n";
444 0           $extension .= " $price\n";
445 0           $extension .= " \n";
446             }
447              
448 0 0         $params->{extension} = $extension if $extension;
449              
450 0           return $self->SUPER::create_domain( $params );
451             }
452              
453              
454             sub get_domain_spec_ext {
455 0     0 1   my ( undef, $ext ) = @_;
456              
457 0           my %info;
458              
459 0 0         if ( $ext =~ /(.+?)<\/idn:data>/s ) {
460 0           my $idn = $1;
461              
462 0           ( $info{uname} ) = $idn =~ /([^<>]+)<\/idn:uname>/;
463             }
464              
465 0           return \%info;
466             }
467              
468              
469             sub renew_domain {
470 0     0 1   my ( $self, $params ) = @_;
471              
472 0           my $extension = '';
473              
474 0 0 0       if ( $params->{price} or $params->{fee} ) {
475 0   0       my $price = $params->{price} || $params->{fee};
476             # Russian Ruble only
477 0           $extension .= qq| \n|;
478 0           $extension .= " RUB\n";
479 0           $extension .= " $price\n";
480 0           $extension .= " \n";
481             }
482              
483 0 0         $params->{extension} = $extension if $extension;
484              
485 0           return $self->SUPER::renew_domain( $params );
486             }
487              
488              
489             =head2 restore_domain
490              
491             first call for restore_domain
492              
493             =cut
494              
495             sub restore_domain {
496 0     0 1   my ( $self, $params ) = @_;
497              
498 0           $params->{extension} = qq|
499            
500             |;
501              
502 0           return $self->SUPER::update_domain( $params );
503             }
504              
505              
506             =head2 confirmations_restore_domain
507              
508             Second call for restore_domain
509              
510             =over 4
511              
512             =item C
513              
514             whois before delete;
515              
516             =item C
517              
518             whois on now;
519              
520             =item C
521              
522             delete domain date-time, see. upd_date in domain:info before call restore_domain;
523              
524             =item C
525              
526             restore request call datetime in UTC;
527              
528             =item C
529              
530             restore reason,
531              
532             variants: C, C, C;
533              
534             =item C
535              
536             need to write what it is for the client;
537              
538             =item C
539              
540             can and without other.
541              
542             =back
543              
544             =cut
545              
546             sub confirmations_restore_domain {
547 0     0 1   my ( $self, $params ) = @_;
548              
549 0           $params->{extension} = <
550            
551            
552            
553             $$params{pre_data}
554             $$params{post_data}
555             $$params{del_time}
556             $$params{rest_time}
557             $$params{reason}
558             $$params{statement}
559            
560            
561            
562            
563             RGPEXT
564              
565 0           return $self->SUPER::update_domain( $params );
566             }
567              
568              
569             1;
570              
571              
572             __END__