perl / Git / SVN / Prompt.pmon commit Merge branch 'jk/smart-http-switch' (fb1e4a8)
   1package Git::SVN::Prompt;
   2use strict;
   3use warnings;
   4require SVN::Core;
   5use vars qw/$_no_auth_cache $_username/;
   6
   7sub simple {
   8        my ($cred, $realm, $default_username, $may_save, $pool) = @_;
   9        $may_save = undef if $_no_auth_cache;
  10        $default_username = $_username if defined $_username;
  11        if (defined $default_username && length $default_username) {
  12                if (defined $realm && length $realm) {
  13                        print STDERR "Authentication realm: $realm\n";
  14                        STDERR->flush;
  15                }
  16                $cred->username($default_username);
  17        } else {
  18                username($cred, $realm, $may_save, $pool);
  19        }
  20        $cred->password(_read_password("Password for '" .
  21                                       $cred->username . "': ", $realm));
  22        $cred->may_save($may_save);
  23        $SVN::_Core::SVN_NO_ERROR;
  24}
  25
  26sub ssl_server_trust {
  27        my ($cred, $realm, $failures, $cert_info, $may_save, $pool) = @_;
  28        $may_save = undef if $_no_auth_cache;
  29        print STDERR "Error validating server certificate for '$realm':\n";
  30        {
  31                no warnings 'once';
  32                # All variables SVN::Auth::SSL::* are used only once,
  33                # so we're shutting up Perl warnings about this.
  34                if ($failures & $SVN::Auth::SSL::UNKNOWNCA) {
  35                        print STDERR " - The certificate is not issued ",
  36                            "by a trusted authority. Use the\n",
  37                            "   fingerprint to validate ",
  38                            "the certificate manually!\n";
  39                }
  40                if ($failures & $SVN::Auth::SSL::CNMISMATCH) {
  41                        print STDERR " - The certificate hostname ",
  42                            "does not match.\n";
  43                }
  44                if ($failures & $SVN::Auth::SSL::NOTYETVALID) {
  45                        print STDERR " - The certificate is not yet valid.\n";
  46                }
  47                if ($failures & $SVN::Auth::SSL::EXPIRED) {
  48                        print STDERR " - The certificate has expired.\n";
  49                }
  50                if ($failures & $SVN::Auth::SSL::OTHER) {
  51                        print STDERR " - The certificate has ",
  52                            "an unknown error.\n";
  53                }
  54        } # no warnings 'once'
  55        printf STDERR
  56                "Certificate information:\n".
  57                " - Hostname: %s\n".
  58                " - Valid: from %s until %s\n".
  59                " - Issuer: %s\n".
  60                " - Fingerprint: %s\n",
  61                map $cert_info->$_, qw(hostname valid_from valid_until
  62                                       issuer_dname fingerprint);
  63        my $choice;
  64prompt:
  65        print STDERR $may_save ?
  66              "(R)eject, accept (t)emporarily or accept (p)ermanently? " :
  67              "(R)eject or accept (t)emporarily? ";
  68        STDERR->flush;
  69        $choice = lc(substr(<STDIN> || 'R', 0, 1));
  70        if ($choice =~ /^t$/i) {
  71                $cred->may_save(undef);
  72        } elsif ($choice =~ /^r$/i) {
  73                return -1;
  74        } elsif ($may_save && $choice =~ /^p$/i) {
  75                $cred->may_save($may_save);
  76        } else {
  77                goto prompt;
  78        }
  79        $cred->accepted_failures($failures);
  80        $SVN::_Core::SVN_NO_ERROR;
  81}
  82
  83sub ssl_client_cert {
  84        my ($cred, $realm, $may_save, $pool) = @_;
  85        $may_save = undef if $_no_auth_cache;
  86        print STDERR "Client certificate filename: ";
  87        STDERR->flush;
  88        chomp(my $filename = <STDIN>);
  89        $cred->cert_file($filename);
  90        $cred->may_save($may_save);
  91        $SVN::_Core::SVN_NO_ERROR;
  92}
  93
  94sub ssl_client_cert_pw {
  95        my ($cred, $realm, $may_save, $pool) = @_;
  96        $may_save = undef if $_no_auth_cache;
  97        $cred->password(_read_password("Password: ", $realm));
  98        $cred->may_save($may_save);
  99        $SVN::_Core::SVN_NO_ERROR;
 100}
 101
 102sub username {
 103        my ($cred, $realm, $may_save, $pool) = @_;
 104        $may_save = undef if $_no_auth_cache;
 105        if (defined $realm && length $realm) {
 106                print STDERR "Authentication realm: $realm\n";
 107        }
 108        my $username;
 109        if (defined $_username) {
 110                $username = $_username;
 111        } else {
 112                print STDERR "Username: ";
 113                STDERR->flush;
 114                chomp($username = <STDIN>);
 115        }
 116        $cred->username($username);
 117        $cred->may_save($may_save);
 118        $SVN::_Core::SVN_NO_ERROR;
 119}
 120
 121sub _read_password {
 122        my ($prompt, $realm) = @_;
 123        my $password = '';
 124        if (exists $ENV{GIT_ASKPASS}) {
 125                open(PH, "-|", $ENV{GIT_ASKPASS}, $prompt);
 126                $password = <PH>;
 127                $password =~ s/[\012\015]//; # \n\r
 128                close(PH);
 129        } else {
 130                print STDERR $prompt;
 131                STDERR->flush;
 132                require Term::ReadKey;
 133                Term::ReadKey::ReadMode('noecho');
 134                while (defined(my $key = Term::ReadKey::ReadKey(0))) {
 135                        last if $key =~ /[\012\015]/; # \n\r
 136                        $password .= $key;
 137                }
 138                Term::ReadKey::ReadMode('restore');
 139                print STDERR "\n";
 140                STDERR->flush;
 141        }
 142        $password;
 143}
 144
 1451;
 146__END__
 147
 148Git::SVN::Prompt - authentication callbacks for git-svn
 149
 150=head1 SYNOPSIS
 151
 152    use Git::SVN::Prompt qw(simple ssl_client_cert ssl_client_cert_pw
 153                            ssl_server_trust username);
 154    use SVN::Client ();
 155
 156    my $cached_simple = SVN::Client::get_simple_provider();
 157    my $git_simple = SVN::Client::get_simple_prompt_provider(\&simple, 2);
 158    my $cached_ssl = SVN::Client::get_ssl_server_trust_file_provider();
 159    my $git_ssl = SVN::Client::get_ssl_server_trust_prompt_provider(
 160        \&ssl_server_trust);
 161    my $cached_cert = SVN::Client::get_ssl_client_cert_file_provider();
 162    my $git_cert = SVN::Client::get_ssl_client_cert_prompt_provider(
 163        \&ssl_client_cert, 2);
 164    my $cached_cert_pw = SVN::Client::get_ssl_client_cert_pw_file_provider();
 165    my $git_cert_pw = SVN::Client::get_ssl_client_cert_pw_prompt_provider(
 166        \&ssl_client_cert_pw, 2);
 167    my $cached_username = SVN::Client::get_username_provider();
 168    my $git_username = SVN::Client::get_username_prompt_provider(
 169        \&username, 2);
 170
 171    my $ctx = new SVN::Client(
 172        auth => [
 173            $cached_simple, $git_simple,
 174            $cached_ssl, $git_ssl,
 175            $cached_cert, $git_cert,
 176            $cached_cert_pw, $git_cert_pw,
 177            $cached_username, $git_username
 178        ]);
 179
 180=head1 DESCRIPTION
 181
 182This module is an implementation detail of the "git svn" command.
 183It implements git-svn's authentication policy.  Do not use it unless
 184you are developing git-svn.
 185
 186The interface will change as git-svn evolves.
 187
 188=head1 DEPENDENCIES
 189
 190L<SVN::Core>.
 191
 192=head1 SEE ALSO
 193
 194L<SVN::Client>.
 195
 196=head1 INCOMPATIBILITIES
 197
 198None reported.
 199
 200=head1 BUGS
 201
 202None.