1
+package Git::SVN::Prompt;
2
+use strict;
3
+use warnings;
4
+require SVN::Core;
5
+use vars qw/$_no_auth_cache $_username/;
6
+
7
+sub 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
+
26
+sub 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;
64
+prompt:
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
+
83
+sub 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
+
94
+sub 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
+
102
+sub 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
+
121
+sub _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
+
145
+1;
146
+__END__
147
+
148
+Git::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
+
182
+This module is an implementation detail of the "git svn" command.
183
+It implements git-svn's authentication policy. Do not use it unless
184
+you are developing git-svn.
185
+
186
+The interface will change as git-svn evolves.
187
+
188
+=head1 DEPENDENCIES
189
+
190
+L<SVN::Core>.
191
+
192
+=head1 SEE ALSO
193
+
194
+L<SVN::Client>.
195
+
196
+=head1 INCOMPATIBILITIES
197
+
198
+None reported.
199
+
200
+=head1 BUGS
201
+
202
+None.