diff options
Diffstat (limited to 'FS/FS/part_export/domreg_net_dri.pm')
-rw-r--r-- | FS/FS/part_export/domreg_net_dri.pm | 614 |
1 files changed, 0 insertions, 614 deletions
diff --git a/FS/FS/part_export/domreg_net_dri.pm b/FS/FS/part_export/domreg_net_dri.pm deleted file mode 100644 index bf01602..0000000 --- a/FS/FS/part_export/domreg_net_dri.pm +++ /dev/null @@ -1,614 +0,0 @@ -package FS::part_export::domreg_net_dri; - -use vars qw(@ISA %info %options $conf); -use Tie::IxHash; -use FS::part_export::null; - -=head1 NAME - -FS::part_export::domreg_net_dri - Register or transfer domains with Net::DRI - -=head1 DESCRIPTION - -This module handles registering and transferring domains with select registrars or registries supported -by L<Net::DRI>. - -As a part_export, this module can be designated for use with svc_domain services. When the svc_domain object -is inserted into the Freeside database, registration or transferring of the domain may be initiated, depending -on the setting of the svc_domain's action field. Further operations can be performed from the View Domain screen. - -Logging information is written to the Freeside log folder. - -For correct operation you must add name/value pairs to the protcol and transport options fields. The setttings -depend on the domain registry driver (DRD) selected. - -=over 4 - -=item N - Register the domain - -=item M - Transfer the domain - -=item I - Ignore the domain for registration purposes - -=back - -=cut - -@ISA = qw(FS::part_export::null); - -my @tldlist = qw/com net org biz info name mobi at be ca cc ch cn de dk es eu fr it mx nl tv uk us/; - -my $opensrs_protocol_opts=<<'END'; -username= -password= -auto_renew=0 -affiliate_id= -reseller_id= -END - -my $opensrs_transport_opts=<<'END'; -client_login= -client_password= -END - -tie %options, 'Tie::IxHash', - 'drd' => { label => 'Domain Registry Driver (DRD)', - type => 'select', - options => [ qw/BookMyName CentralNic Gandi OpenSRS OVH VNDS/ ], - default => 'OpenSRS' }, - 'log_level' => { label => 'Logging', - type => 'select', - options => [ qw/debug info notice warning error critical alert emergency/ ], - default => 'warning' }, - 'protocol_opts' => { - label => 'Protocol Options', - type => 'textarea', - default => $opensrs_protocol_opts, - }, - 'transport_opts' => { - label => 'Transport Options', - type => 'textarea', - default => $opensrs_transport_opts, - }, -# 'register' => { label => 'Use for registration', -# type => 'checkbox', -# default => '1' }, -# 'transfer' => { label => 'Use for transfer', -# type => 'checkbox', -# default => '1' }, -# 'delete' => { label => 'Use for deletion', -# type => 'checkbox', -# default => '1' }, -# 'renew' => { label => 'Use for renewals', -# type => 'checkbox', -# default => '1' }, - 'tlds' => { label => 'Use this export for these top-level domains (TLDs)', - type => 'select', - multi => 1, - size => scalar(@tldlist), - options => [ @tldlist ], - default => 'com net org' }, -; - -my $opensrs_protocol_defaults = $opensrs_protocol_opts; -$opensrs_protocol_defaults =~ s|\n|\\n|g; - -my $opensrs_transport_defaults = $opensrs_transport_opts; -$opensrs_transport_defaults =~ s|\n|\\n|g; - -%info = ( - 'svc' => 'svc_domain', - 'desc' => 'Domain registration via Net::DRI', - 'options' => \%options, - 'notes' => <<"END" -Registers and transfers domains via a Net::DRI registrar or registry. -<a href="http://search.cpan.org/search?dist=Net-DRI">Net::DRI</a> -must be installed. You must have an account at the selected registrar/registry. -<BR /> -Some top-level domains have additional business rules not supported by this export. These TLDs cannot be registered or transfered with this export. -<BR><BR>Use these buttons for some useful presets: -<UL> - <LI> - <INPUT TYPE="button" VALUE="OpenSRS Live System (rr-n1-tor.opensrs.net)" onClick=' - document.dummy.machine.value = "rr-n1-tor.opensrs.net"; - this.form.machine.value = "rr-n1-tor.opensrs.net"; - '> - <LI> - <INPUT TYPE="button" VALUE="OpenSRS Test System (horizon.opensrs.net)" onClick=' - document.dummy.machine.value = "horizon.opensrs.net"; - this.form.machine.value = "horizon.opensrs.net"; - '> - <LI> - <INPUT TYPE="button" VALUE="OpenSRS protocol/transport options" onClick=' - this.form.protocol_opts.value = "$opensrs_protocol_defaults"; - this.form.transport_opts.value = "$opensrs_transport_defaults"; - '> -</UL> -END -); - -install_callback FS::UID sub { - $conf = new FS::Conf; -}; - -#sub rebless { shift; } - -# experiment: want the status of these right away, so no queueing - -sub _export_insert { - my( $self, $svc_domain ) = ( shift, shift ); - - return if $svc_domain->action eq 'I'; # Ignoring registration, just doing DNS - - if ($svc_domain->action eq 'N') { - return $self->register( $svc_domain ); - } elsif ($svc_domain->action eq 'M') { - return $self->transfer( $svc_domain ); - } - return "Unknown domain action " . $svc_domain->action; -} - -=item get_portfolio_credentials - -Returns, in list context, the user name and password for the domain portfolio. - -This is currently specified via the username and password keys in the protocol options. - -=cut - -sub get_portfolio_credentials { - my $self = shift; - - my %opts = $self->get_protocol_options(); - return ($opts{username}, $opts{password}); -} - -=item format_tel - -Reformats a phone number according to registry rules. Currently Freeside stores phone numbers -in NANPA format and most registries prefer "+CCC.NPANPXNNNN" - -=cut - -sub format_tel { - my $tel = shift; - - #if ($tel =~ /^(\d{3})-(\d{3})-(\d{4})\s*(x\s*(\d+))?$/) { - if ($tel =~ /^(\d{3})-(\d{3})-(\d{4})$/) { - $tel = "+1.$1$2$3"; # TBD: other country codes -# if $tel .= "$4" if $4; - } - return $tel; -} - -sub gen_contact_set { - my ($self, $dri, $cust_main) = @_; - - my @invoicing_list = $cust_main->invoicing_list_emailonly; - if ( $conf->exists('emailinvoiceautoalways') - || $conf->exists('emailinvoiceauto') && ! @invoicing_list - || ( $conf->exists('emailinvoiceonly') && ! @invoicing_list ) ) { - push @invoicing_list, $cust_main->all_emails; - } - - my $email = ($conf->exists('business-onlinepayment-email-override')) - ? $conf->config('business-onlinepayment-email-override') - : $invoicing_list[0]; - - my $cs=$dri->local_object('contactset'); - my $co=$dri->local_object('contact'); - - my ($user, $pass) = $self->get_portfolio_credentials(); - - $co->srid($user); # Portfolio user name for OpenSRS? - $co->auth($pass); # Portfolio password for OpenSRS? - - $co->firstname($cust_main->first); - $co->name($cust_main->last); - $co->org($cust_main->company || '-'); - $co->street([$cust_main->address1, $cust_main->address2]); - $co->city($cust_main->city); - $co->sp($cust_main->state); - $co->pc($cust_main->zip); - $co->cc($cust_main->country); - $co->voice(format_tel($cust_main->daytime())); - $co->email($email); - - $cs->set($co, 'registrant'); - $cs->set($co, 'admin'); - $cs->set($co, 'billing'); - - return $cs; -} - -=item validate_contact_set - -Attempts to validate contact data for the domain based on OpenSRS rules. - -Returns undef if the contact data is acceptable, an error message if the contact -data lacks one or more required fields. - -=cut - -sub validate_contact_set { - my $c = shift; - - my %fields = ( - firstname => "first name", - name => "last name", - street => "street address", - city => "city", - sp => "state", - pc => "ZIP/postal code", - cc => "country", - email => "email address", - voice => "phone number", - ); - my @err = (); - foreach my $which (qw/registrant admin billing/) { - my $co = $c->get($which); - foreach (keys %fields) { - if (!$co->$_()) { - push @err, $fields{$_}; - } - } - } - if (scalar(@err) > 0) { - return "Contact information needs: " . join(', ', @err); - } - undef; -} - -#sub _export_replace { -# my( $self, $new, $old ) = (shift, shift, shift); -# -# return ''; -# -#} - -## Domain registration exports do nothing on delete. You're just removing the domain from Freeside, not the registry -#sub _export_delete { -# my( $self, $www ) = ( shift, shift ); -# -# return ''; -#} - -=item split_textarea_options - -Split textarea contents into lines, split lines on =, and then trim the results; - -=cut - -sub split_textarea_options { - my ($self, $optname) = @_; - my %opts = map { - my ($key, $value) = split /=/, $_; - $key =~ s/^\s*//; - $key =~ s/\s*$//; - $value =~ s/^\s*//; - $value =~ s/\s*$//; - $key => $value } split /\n/, $self->option($optname); - %opts; -} - -=item get_protocol_options - -Return a hash of protocol options - -=cut - -sub get_protocol_options { - my $self = shift; - my %opts = $self->split_textarea_options('protocol_opts'); - if ($self->machine =~ /opensrs\.net/) { - my %topts = $self->get_transport_options; - $opts{reseller_id} = $topts{client_login}; - } - %opts; -} - -=item get_transport_options - -Return a hash of transport options - -=cut - -sub get_transport_options { - my $self = shift; - my %opts = $self->split_textarea_options('transport_opts'); - $opts{remote_url} = "https://" . $self->machine . ":55443/resellers" if $self->machine =~ /opensrs\.net/; - %opts; -} - -=item is_supported_domain - -Return undef if the domain name uses a TLD or SLD that is supported by this registrar. -Otherwise return an error message explaining what's wrong. - -=cut - -sub is_supported_domain { - my $self = shift; - my $svc_domain = shift; - - # Get the TLD of the new domain - my @bits = split /\./, $svc_domain->domain; - - return "Can't register subdomains: " . $svc_domain->domain if scalar(@bits) != 2; - - my $tld = pop @bits; - - # See if it's one this export supports - my @tlds = split /\s+/, $self->option('tlds'); - @tlds = map { s/\.//; $_ } @tlds; - return "Can't register top-level domain $tld, restricted to: " . $self->option('tlds') if ! grep { $_ eq $tld } @tlds; - return undef; -} - -=item get_dri - -=cut - -sub get_dri { - my $self = shift; - my $dri; - -# return $self->{dri} if $self->{dri}; #!!!TBD!!! connection caching. - - eval "use Net::DRI 0.95;"; - return $@ if $@; - -# $dri=Net::DRI->new(...) to create the global object. Save the result, - - eval { - #$dri = Net::DRI::TrapExceptions->new(10); - $dri = Net::DRI->new({logging => [ 'files', { output_directory => '%%%FREESIDE_LOG%%%' } ]}); #!!!TBD!!! - $dri->logging->level( $self->option('log_level') ); - $dri->add_registry( $self->option('drd') ); - my $protocol; - $protocol = 'xcp' if $self->option('drd') eq 'OpenSRS'; - - $dri->target( $self->option('drd') )->add_current_profile($self->option('drd') . '1', -# 'Net::DRI::Protocol::' . $self->option('protocol_type'), -# $self->option('protocol_type'), -# 'xcp', #TBD!!!! - $protocol, # Implies transport -# 'Net::DRI::Transport::' . $self->option('transport_type'), - { $self->get_transport_options() }, -# [ $self->get_protocol_options() ] - ); - }; - return $@ if $@; - - $self->{dri} = $dri; - return $dri; -} - -=item get_status - -Returns a reference to a hashref containing information on the domain's status. The keys -defined depend on the status. - -'unregistered' means the domain is not registered. - -Otherwise, if the domain is in an asynchronous operation such as a transfer, returns the state -of that operation. - -Otherwise returns a value indicating if the domain can be managed through our reseller account. - -=cut - -sub get_status { - my ( $self, $svc_domain ) = @_; - my $rc; - my $rslt = {}; - - my $dri = $self->get_dri; - - if (UNIVERSAL::isa($dri, 'Net::DRI::Exception')) { - $rslt->{'message'} = $dri->as_string; - return $rslt; - } - eval { - $rc = $dri->domain_check( $svc_domain->domain ); - if (!$rc->is_success()) { - # Problem accessing the registry/registrar - $rslt->{'message'} = $rc->message; - } elsif (!$dri->get_info('exist')) { - # Domain is not registered - $rslt->{'unregistered'} = 1; - } else { - $rc = $dri->domain_transfer_query( $svc_domain->domain ); - if ($rc->is_success() && $dri->get_info('status')) { - # Transfer in progress - $rslt->{status} = $dri->get_info('status'); - $rslt->{contact_email} = $dri->get_info('request_address'); - $rslt->{last_update_time} = $dri->get_info('unixtime'); - } elsif ($dri->get_info('reason')) { - $rslt->{'reason'} = $dri->get_info('reason'); - # Domain is not being transferred... - $rc = $dri->domain_info( $svc_domain->domain, { $self->get_protocol_options() } ); - if ($rc->is_success() && $dri->get_info('exDate')) { - $rslt->{'expdate'} = $dri->get_info('exDate'); - } - } else { - $rslt->{status} = 'Unknown'; - } - } - }; -# rslt->{'message'} = $@->as_string if $@; - if ($@) { - $rslt->{'message'} = (UNIVERSAL::isa($@, 'Net::DRI::Exception')) ? $@->as_string : $@->message; - } - - return $rslt; # Success -} - -=item register - -Attempts to register the domain through the reseller account associated with this export. - -Like most export functions, returns an error message on failure or undef on success. - -=cut - -sub register { - my ( $self, $svc_domain, $years ) = @_; - - my $err = $self->is_supported_domain( $svc_domain ); - return $err if $err; - - my $dri = $self->get_dri; - return $dri->as_string if (UNIVERSAL::isa($dri, 'Net::DRI::Exception')); - - eval { # All $dri methods can throw an exception. - -# Call methods - my $cust_main = $svc_domain->cust_svc->cust_pkg->cust_main; - - my $cs = $self->gen_contact_set($dri, $cust_main); - - $err = validate_contact_set($cs); - return $err if $err; - -# !!!TBD!!! add custom name servers when supported; add ns => $ns to hash passed to domain_create - - $res = $dri->domain_create($svc_domain->domain, { $self->get_protocol_options(), pure_create => 1, contact => $cs, duration => DateTime::Duration->new(years => $years) }); - $err = $res->is_success ? '' : $res->message; - }; - if ($@) { - $err = (UNIVERSAL::isa($@, 'Net::DRI::Exception')) ? $@->msg : $@->message; - } - - return $err; -} - -=item transfer - -Attempts to transfer the domain into the reseller account associated with this export. - -Like most export functions, returns an error message on failure or undef on success. - -=cut - -sub transfer { - my ( $self, $svc_domain ) = @_; - - my $err = $self->is_supported_domain( $svc_domain ); - return $err if $err; - -# $dri=Net::DRI->new(...) to create the global object. Save the result, - my $dri = $self->get_dri; - return $dri->as_string if (UNIVERSAL::isa($dri, 'Net::DRI::Exception')); - - eval { # All $dri methods can throw an exception - -# Call methods - my $cust_main = $svc_domain->cust_svc->cust_pkg->cust_main; - - my $cs = $self->gen_contact_set($dri, $cust_main); - - $err = validate_contact_set($cs); - return $err if $err; - -# !!!TBD!!! add custom name servers when supported; add ns => $ns to hash passed to domain_transfer_start - - $res = $dri->domain_transfer_start($svc_domain->domain, { $self->get_protocol_options(), contact => $cs }); - $err = $res->is_success ? '' : $res->message; - }; - if ($@) { - $err = (UNIVERSAL::isa($@, 'Net::DRI::Exception')) ? $@->msg : $@->message; - } - - return $err; -} - -=item renew - -Attempts to renew the domain for the specified number of years. - -Like most export functions, returns an error message on failure or undef on success. - -=cut - -sub renew { - my ( $self, $svc_domain, $years ) = @_; - - my $err = $self->is_supported_domain( $svc_domain ); - return $err if $err; - - my $dri = $self->get_dri; - return $dri->as_string if (UNIVERSAL::isa($dri, 'Net::DRI::Exception')); - - eval { # All $dri methods can throw an exception - my $expdate; - my $res = $dri->domain_info( $svc_domain->domain, { $self->get_protocol_options() } ); - if ($res->is_success() && $dri->get_info('exDate')) { - $expdate = $dri->get_info('exDate'); - -# return "Domain renewal not enabled" if !$self->option('renew'); - $res = $dri->domain_renew( $svc_domain->domain, { $self->get_protocol_options(), duration => DateTime::Duration->new(years => $years), current_expiration => $expdate }); - } - $err = $res->is_success ? '' : $res->message; - }; - if ($@) { - $err = (UNIVERSAL::isa($@, 'Net::DRI::Exception')) ? $@->msg : $@->message; - } - - return $err; -} - -=item revoke - -Attempts to revoke the domain registration. Only succeeds if invoked during the DRI -grace period immediately after registration. - -Like most export functions, returns an error message on failure or undef on success. - -=cut - -sub revoke { - my ( $self, $svc_domain ) = @_; - - my $err = $self->is_supported_domain( $svc_domain ); - return $err if $err; - - my $dri = $self->get_dri; - return $dri->as_string if (UNIVERSAL::isa($dri, 'Net::DRI::Exception')); - - eval { # All $dri methods can throw an exception - -# return "Domain registration revocation not enabled" if !$self->option('revoke'); - my $res = $dri->domain_delete( $svc_domain->domain, { $self->get_protocol_options(), domain => $svc_domain->domain, pure_delete => 1 }); - $err = $res->is_success ? '' : $res->message; - }; - if ($@) { - $err = (UNIVERSAL::isa($@, 'Net::DRI::Exception')) ? $@->msg : $@->message; - } - - return $err; -} - -=item registrar - -Should return a full-blown object representing the Net::DRI DRD, but current just returns a hashref -containing the registrar name. - -=cut - -sub registrar { - my $self = shift; - return { - name => $self->option('drd'), - }; -} - -=head1 SEE ALSO - -L<FS::part_export_option>, L<FS::export_svc>, L<FS::svc_domain>, -L<FS::Record>, schema.html from the base documentation. - -=cut - -1; - |