App-pepper

 view release on metacpan or  search on metacpan

lib/App/pepper.pm  view on Meta::CPAN

package App::pepper;
use App::pepper::EPPClient;
use App::pepper::Highlighter;
use File::Temp qw(tmpnam);
use Getopt::Long;
use Mozilla::CA;
use Net::EPP::Simple;
use List::Util qw(none);
use Pod::Usage;
use Term::ANSIColor;
use Term::ReadLine;
use Text::ParseWords;
use XML::LibXML;
use strict;
use constant {
    SECURE_AUTHINFO_XMLNS => 'urn:ietf:params:xml:ns:epp:secure-authinfo-transfer-1.0',
};
use vars qw($VERSION);

our $VERSION = '1.0.0';

my $opt = {
    'port'      => 700,
    'timeout'   => 3,
    'lang'      => 'en',
};

my $result = GetOptions($opt,
    'host=s',
    'user=s',
    'pass=s',
    'newpw=s',
    'exec=s',
    'port=i',
    'timeout=i',
    'help',
    'insecure',
    'lang=s',
    'debug',
    'cert=s',
    'key=s',
    'login-security',
    'nossl',
);

if (!$result || $opt->{'help'}) {
    pod2usage(
        '-verbose'    => 99,
        '-sections'    => 'USAGE',
        '-input'    => __FILE__,
    );
    exit;
}

my $handlers = {
    'timeout'        => \&handle_timeout,
    'ssl'            => \&handle_ssl,
    'host'            => \&handle_host,
    'port'            => \&handle_port,
    'credentials'    => \&handle_credentials,
    'id'            => \&handle_id,
    'pw'            => \&handle_pw,
    'newpw'            => \&handle_newpw,
    'connect'        => \&handle_connect,
    'login'            => \&handle_login,
    'logout'        => \&handle_logout,
    'hello'            => \&handle_hello,
    'check'            => \&handle_check,
    'info'            => \&handle_info,
    'poll'            => \&handle_poll,
    'help'            => \&handle_help,
    'send'            => \&handle_send,
    'BEGIN'            => \&handle_begin,
    'exit'            => \&handle_exit,
    'transfer'        => \&handle_transfer,
    'clone'            => \&handle_clone,
    'delete'        => \&handle_delete,
    'renew'            => \&handle_renew,
    'create'        => \&handle_create,
    'edit'            => \&handle_edit,
    'cert'            => \&handle_cert,
    'key'            => \&handle_key,
    'restore'        => \&handle_restore,
    'update'        => \&handle_update,
};

our $term;
$term = Term::ReadLine->new('pepper') if (-t STDIN && -t STDOUT);

my $outfh = ($term ? \*STDOUT : \*STDERR);

my $prompt = 'pepper> ';

my $histfile = $ENV{'HOME'}.'/.pepper_history';

my $xml = XML::LibXML->new;

if ($term) {
    $term->ReadHistory($histfile) if ('Term::ReadLine::Gnu' eq $term->ReadLine);

    note('Welcome to pepper!');

    note(color('yellow').'> For best results, install Term::ReadLine::Gnu <'.color('reset')) if ($term && 'Term::ReadLine::Gnu' ne $term->ReadLine);
}

my $epp = App::pepper::EPPClient->new(
    'host'                => '',
    'connect'            => undef,
    'debug'                => $opt->{'debug'},
    'login'                => undef,
    'reconnect'            => 0,
    'verify'            => ($opt->{'insecure'} ? undef : 1),
    'ca_file'            => Mozilla::CA::SSL_ca_file(),
    'lang'                => ($opt->{'lang'} ? $opt->{'lang'} : 'en'),
    'appname'           => sprintf('Pepper %s', $VERSION),
    'login_security'    => $opt->{'login-security'},
);

execute_command('ssl off')                                                if ($opt->{'nossl'});
execute_command(sprintf('timeout %d',    $opt->{'timeout'}))                if ($opt->{'timeout'});

lib/App/pepper.pm  view on Meta::CPAN

        note('SSL enabled');

    } elsif ($_[0] eq 'off') {
        $epp->{'ssl'} = 0;
        note('SSL disabled');

    } else {
        return error("Invalid SSL mode '%s'", $_[0]);

    }
    return 1;
}

sub handle_host {
    if ($epp->connected) {
        return error("Already connected");

    } else {
        $epp->{'host'} = $_[0];
        note("Host set to %s", $_[0]);
        return 1;
    }
}

sub handle_port {
    if ($epp->connected) {
        return error("Already connected");

    } else {
        $epp->{'port'} = int($_[0]);
        note("Port set to %d", $_[0]);
        return 1;
    }
}

sub handle_connect {
    if ($epp->connected) {
        return error("Already connected");

    } elsif ($epp->{'host'} eq '') {
        return error('No host specified');

    } else {
        note('Connecting to %s...', $epp->{'host'});

        $epp->{'quiet'} = 1;
        my $result = $epp->_connect(undef);
        $epp->{'quiet'} = 0;

        if ($result) {
            note("Connected OK. Type 'hello' to see the greeting frame.");

        } else {
            error("Unable to connect: %s", $Net::EPP::Simple::Message);

        }
        return $result;
    }
}

sub handle_credentials {
    if ($_[0] eq '') {
        return error('Missing client ID');

    } elsif ($_[1] eq '') {
        return error('Missing password');

    } else {
        handle_id($_[0]) && handle_pw($_[1]);
        return 1;

    }
}

sub handle_id {
    if ($epp->authenticated) {
        return error("Already authenticated");

    } else {
        $epp->{'user'} = shift;
        note("User ID set to '%s'", $epp->{'user'});
    }
}

sub handle_pw {
    if ($epp->authenticated) {
        return error("Already authenticated");

    } else {
        $epp->{'pass'} = shift;
        note("Password set to '%s'", ('*' x length($epp->{'pass'})));

    }
}

sub handle_newpw {
    if ($epp->authenticated) {
        return error("Already authenticated");

    } else {
        $epp->{'newPW'} = shift;
        note("New password set to '%s'", ('*' x length($epp->{'newPW'})));

    }
}

sub handle_login {
    my $verbose = shift;
    if (!$epp->connected) {
        return handle_connect() && handle_login();

    } elsif ($epp->authenticated) {
        return error('Already logged in');

    } elsif ($epp->{'host'} eq '') {
        return error('No host specified');

    } elsif ($epp->{'user'} eq '' || $epp->{'pass'} eq '') {
        return error('No credentials specified');

    } else {
        note("Attempting to login as '%s'...", $epp->{'user'});
        $epp->{'quiet'} = ($verbose ? 0 : 1);
        my $result = $epp->_login;
        $epp->{'quiet'} = 0;
        if ($result) {
            note('Logged in OK!');

        } else {
            error("%s%04d%s %s", color($Net::EPP::Simple::Code < 2000 ? 'green' : 'red'), $Net::EPP::Simple::Code, color('reset'), $Net::EPP::Simple::Message);

        }
        return $result;
    }
}

sub handle_logout {
    if (!$epp->authenticated) {
        return error('Not logged in');

    } else {
        note('logging out');
        $epp->{'quiet'} = 1;
        my $result = $epp->logout;
        $epp->{'quiet'} = 0;
        note("%s%04d%s %s", color($Net::EPP::Simple::Code < 2000 ? 'green' : 'red'), $Net::EPP::Simple::Code, color('reset'), $Net::EPP::Simple::Message);
        return $result;
    }
}

sub handle_hello {
    if (!$epp->connected) {
        return error('Not connected');

    } else {
        return $epp->ping;

    }
}

sub handle_check {
    if (!$epp->authenticated) {
        return error('Not connected');

    } else {
        my ($type, $id, @extra) = @_;
        if ($type eq 'domain') {
            return $epp->check_domain($id);

        } elsif ($type eq 'claims') {
            return handle_claims_check($id);

        } elsif ($type eq 'fee') {
            return handle_fee_check($id, @extra);

        } elsif ($type eq 'host') {
            return $epp->check_host($id);

        } elsif ($type eq 'contact') {

lib/App/pepper.pm  view on Meta::CPAN

        my $frame;
        eval { $frame = $xml->parse_string($buffer) };
        if ($@ || !$frame) {
            $@ =~ s/[\r\n]+$//g;
            error("Unable to parse frame ($@)");

        } else {
            return $epp->request($frame);

        }
    }
}

sub handle_edit {
    if (!$epp->connected) {
        return error('Not connected');

    } else {
        my $file = tmpnam();

        open(FILE, ">$file");
        print FILE Net::EPP::Frame->new('command')->toString(2);
        close(FILE);

        my $cmd = ($ENV{'EDITOR'} || '/usr/bin/vi');
        my ($cmd, @args) = split(/[ \t]+/, $cmd);
        push(@args, $file);

        if (0 != system($cmd, @args)) {
            error("Command '$cmd' exited abnormally");

        } else {
            return send_file($file);

        }
    }
}

sub send_file {
    my $file = shift;
    my $frame;
    eval { $frame = $xml->parse_file($file) };
    if ($@ || !$frame) {
        $@ =~ s/[\r\n]+$//g;
        return error("Unable to parse '$file': $@");

    } else {
        return $epp->request($frame);

    }
}

sub handle_help {
    my $cmd = lc(shift || 'help');

    my %map = (
        'timeout'            => 'SYNTAX/Connection Management',
        'ssl'                => 'SYNTAX/Connection Management',
        'host'                => 'SYNTAX/Connection Management',
        'port'                => 'SYNTAX/Connection Management',
        'credentials'        => 'SYNTAX/Session Management',
        'id'                => 'SYNTAX/Session Management',
        'pw'                => 'SYNTAX/Session Management',
        'newpw'                => 'SYNTAX/Session Management',
        'connect'            => 'SYNTAX/Connection Management',
        'login'                => 'SYNTAX/Session Management',
        'logout'            => 'SYNTAX/Session Management',
        'hello'                => 'SYNTAX/Session Management',
        'check'                => 'SYNTAX/Query Commands/Availability Checks',
        'info'                => 'SYNTAX/Query Commands/Object Information',
        'poll'                => 'SYNTAX/Session Management',
        'help'                => 'SYNTAX/Getting Help',
        'send'                => 'SYNTAX/Miscellaneous Commands',
        'begin'                => 'SYNTAX/Miscellaneous Commands',
        'exit'                => 'SYNTAX/Connection Management',
        'transfer'            => 'SYNTAX/Object Transfers',
        'clone'                => 'SYNTAX/Creating Objects',
        'delete'            => 'SYNTAX/Transform Commands',
        'renew'                => 'SYNTAX/Transform Commands',
        'create'            => 'SYNTAX/Creating Objects',
        'create-domain'        => 'SYNTAX/Creating Objects/Creating Domain Objects',
        'create-host'        => 'SYNTAX/Creating Objects/Creating Host Objects',
        'create-contact'    => 'SYNTAX/Creating Objects/Creating Contact Objects',
        'edit'                => 'SYNTAX/Miscellaneous Commands',
        'cert'                => 'SYNTAX/Connection Management',
        'key'                => 'SYNTAX/Connection Management',
        'restore'            => 'SYNTAX/Transform Commands',
        'update'            => 'SYNTAX/Object Updates',
        'update-domain'        => 'SYNTAX/Object Updates/Domain Updates',
        'update-host'        => 'SYNTAX/Object Updates/Host Updates',
        'update-contact'    => 'SYNTAX/Object Updates/Contact Updates',
    );

    print "\n";

    pod2usage(
        '-verbose'    => 99,
        '-sections'    => $map{$cmd} || $map{'help'},
        '-exitval'    => 'NOEXIT',
        '-input'    => __FILE__,
    );
}

sub handle_exit {
    $epp->{'quiet'} = 1;
    $epp->logout if ($epp->authenticated);
    $epp->disconnect if ($epp->connected);
    note('bye!');
    exit;
}

sub handle_transfer {
    if (!$epp->authenticated) {
        return error('Not connected');

    } else {
        my ($type, $object, $cmd, $authinfo, $period) = @_;

        return error("invalid object type '%s'", $type) if ($type ne 'domain' && $type ne 'contact');
        return error("invalid command '%s'", $cmd) if ($cmd ne 'query' && $cmd ne 'request' && $cmd ne 'cancel' && $cmd ne 'approve' && $cmd ne 'reject');



( run in 1.363 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )