提交 017b7c52 编写于 作者: J Junio C Hamano

Merge branch 'lm/credential-netrc'

Update credential-netrc helper (in contrib/) to allow customizing
the GPG used to decrypt the encrypted .netrc file.

* lm/credential-netrc:
  git-credential-netrc: accept gpg option
  git-credential-netrc: adapt to test framework for git
test: test:
./test.pl ./t-git-credential-netrc.sh
testverbose: testverbose:
./test.pl -d -v ./t-git-credential-netrc.sh -d -v
...@@ -2,11 +2,13 @@ ...@@ -2,11 +2,13 @@
use strict; use strict;
use warnings; use warnings;
use autodie;
use Getopt::Long; use Getopt::Long;
use File::Basename; use File::Basename;
use Git;
my $VERSION = "0.1"; my $VERSION = "0.2";
my %options = ( my %options = (
help => 0, help => 0,
...@@ -54,6 +56,7 @@ GetOptions(\%options, ...@@ -54,6 +56,7 @@ GetOptions(\%options,
"insecure|k", "insecure|k",
"verbose|v", "verbose|v",
"file|f=s@", "file|f=s@",
'gpg|g:s',
); );
if ($options{help}) { if ($options{help}) {
...@@ -62,27 +65,31 @@ if ($options{help}) { ...@@ -62,27 +65,31 @@ if ($options{help}) {
print <<EOHIPPUS; print <<EOHIPPUS;
$0 [-f AUTHFILE1] [-f AUTHFILEN] [-d] [-v] [-k] get $0 [(-f <authfile>)...] [-g <program>] [-d] [-v] [-k] get
Version $VERSION by tzz\@lifelogs.com. License: BSD. Version $VERSION by tzz\@lifelogs.com. License: BSD.
Options: Options:
-f|--file AUTHFILE : specify netrc-style files. Files with the .gpg extension -f|--file <authfile>: specify netrc-style files. Files with the .gpg
will be decrypted by GPG before parsing. Multiple -f extension will be decrypted by GPG before parsing.
arguments are OK. They are processed in order, and the Multiple -f arguments are OK. They are processed in
first matching entry found is returned via the credential order, and the first matching entry found is returned
helper protocol (see below). via the credential helper protocol (see below).
When no -f option is given, .authinfo.gpg, .netrc.gpg, When no -f option is given, .authinfo.gpg, .netrc.gpg,
.authinfo, and .netrc files in your home directory are used .authinfo, and .netrc files in your home directory are
in this order. used in this order.
-k|--insecure : ignore bad file ownership or permissions -g|--gpg <program> : specify the program for GPG. By default, this is the
value of gpg.program in the git repository or global
option or gpg.
-d|--debug : turn on debugging (developer info) -k|--insecure : ignore bad file ownership or permissions
-v|--verbose : be more verbose (show files and information found) -d|--debug : turn on debugging (developer info)
-v|--verbose : be more verbose (show files and information found)
To enable this credential helper: To enable this credential helper:
...@@ -99,8 +106,9 @@ in the path.) ...@@ -99,8 +106,9 @@ in the path.)
git config credential.helper '$shortname -f AUTHFILE -v' git config credential.helper '$shortname -f AUTHFILE -v'
Only "get" mode is supported by this credential helper. It opens every AUTHFILE Only "get" mode is supported by this credential helper. It opens every
and looks for the first entry that matches the requested search criteria: <authfile> and looks for the first entry that matches the requested search
criteria:
'port|protocol': 'port|protocol':
The protocol that will be used (e.g., https). (protocol=X) The protocol that will be used (e.g., https). (protocol=X)
...@@ -120,7 +128,7 @@ host=github.com ...@@ -120,7 +128,7 @@ host=github.com
protocol=https protocol=https
username=tzz username=tzz
this credential helper will look for the first entry in every AUTHFILE that this credential helper will look for the first entry in every <authfile> that
matches matches
machine github.com port https login tzz machine github.com port https login tzz
...@@ -137,8 +145,8 @@ Then, the helper will print out whatever tokens it got from the entry, including ...@@ -137,8 +145,8 @@ Then, the helper will print out whatever tokens it got from the entry, including
back to "protocol". Any redundant entry tokens (part of the original query) are back to "protocol". Any redundant entry tokens (part of the original query) are
skipped. skipped.
Again, note that only the first matching entry from all the AUTHFILEs, processed Again, note that only the first matching entry from all the <authfile>s,
in the sequence given on the command line, is used. processed in the sequence given on the command line, is used.
Netrc/authinfo tokens can be quoted as 'STRING' or "STRING". Netrc/authinfo tokens can be quoted as 'STRING' or "STRING".
...@@ -152,7 +160,7 @@ EOHIPPUS ...@@ -152,7 +160,7 @@ EOHIPPUS
my $mode = shift @ARGV; my $mode = shift @ARGV;
# Credentials must get a parameter, so die if it's missing. # Credentials must get a parameter, so die if it's missing.
die "Syntax: $0 [-f AUTHFILE1] [-f AUTHFILEN] [-d] get" unless defined $mode; die "Syntax: $0 [(-f <authfile>)...] [-d] get" unless defined $mode;
# Only support 'get' mode; with any other unsupported ones we just exit. # Only support 'get' mode; with any other unsupported ones we just exit.
exit 0 unless $mode eq 'get'; exit 0 unless $mode eq 'get';
...@@ -172,6 +180,8 @@ unless (scalar @$files) { ...@@ -172,6 +180,8 @@ unless (scalar @$files) {
$files = $options{file} = [ map { glob $_ } @candidates ]; $files = $options{file} = [ map { glob $_ } @candidates ];
} }
load_config(\%options);
my $query = read_credential_data_from_stdin(); my $query = read_credential_data_from_stdin();
FILE: FILE:
...@@ -233,7 +243,7 @@ sub load_netrc { ...@@ -233,7 +243,7 @@ sub load_netrc {
my $io; my $io;
if ($gpgmode) { if ($gpgmode) {
my @cmd = (qw(gpg --decrypt), $file); my @cmd = ($options{'gpg'}, qw(--decrypt), $file);
log_verbose("Using GPG to open $file: [@cmd]"); log_verbose("Using GPG to open $file: [@cmd]");
open $io, "-|", @cmd; open $io, "-|", @cmd;
} else { } else {
...@@ -410,6 +420,14 @@ sub print_credential_data { ...@@ -410,6 +420,14 @@ sub print_credential_data {
printf "%s=%s\n", $git_token, $entry->{$git_token}; printf "%s=%s\n", $git_token, $entry->{$git_token};
} }
} }
sub load_config {
# load settings from git config
my $options = shift;
# set from command argument, gpg.program option, or default to gpg
$options->{'gpg'} //= Git->repository()->config('gpg.program')
// 'gpg';
log_verbose("using $options{'gpg'} for GPG operations");
}
sub log_verbose { sub log_verbose {
return unless $options{verbose}; return unless $options{verbose};
printf STDERR @_; printf STDERR @_;
......
#!/bin/sh
(
cd ../../../t
test_description='git-credential-netrc'
. ./test-lib.sh
if ! test_have_prereq PERL; then
skip_all='skipping perl interface tests, perl not available'
test_done
fi
perl -MTest::More -e 0 2>/dev/null || {
skip_all="Perl Test::More unavailable, skipping test"
test_done
}
# set up test repository
test_expect_success \
'set up test repository' \
'git config --add gpg.program test.git-config-gpg'
# The external test will outputs its own plan
test_external_has_tap=1
test_external \
'git-credential-netrc' \
perl "$TEST_DIRECTORY"/../contrib/credential/netrc/test.pl
test_done
)
#!/bin/sh
echo machine command-option-gpg login username password password
#!/bin/sh
echo machine git-config-gpg login username password password
#!/usr/bin/perl #!/usr/bin/perl
use lib (split(/:/, $ENV{GITPERLLIB}));
use warnings; use warnings;
use strict; use strict;
use Test; use Test::More qw(no_plan);
use File::Basename;
use File::Spec::Functions qw(:DEFAULT rel2abs);
use IPC::Open2; use IPC::Open2;
BEGIN { plan tests => 15 } BEGIN {
# t-git-credential-netrc.sh kicks off our testing, so we have to go
# from there.
Test::More->builder->current_test(1);
Test::More->builder->no_ending(1);
}
my @global_credential_args = @ARGV; my @global_credential_args = @ARGV;
my $netrc = './test.netrc'; my $scriptDir = dirname rel2abs $0;
print "# Testing insecure file, nothing should be found\n"; my ($netrc, $netrcGpg, $gcNetrc) = map { catfile $scriptDir, $_; }
qw(test.netrc
test.netrc.gpg
git-credential-netrc);
local $ENV{PATH} = join ':'
, $scriptDir
, $ENV{PATH}
? $ENV{PATH}
: ();
diag "Testing insecure file, nothing should be found\n";
chmod 0644, $netrc; chmod 0644, $netrc;
my $cred = run_credential(['-f', $netrc, 'get'], my $cred = run_credential(['-f', $netrc, 'get'],
{ host => 'github.com' }); { host => 'github.com' });
ok(scalar keys %$cred, 0, "Got 0 keys from insecure file"); ok(scalar keys %$cred == 0, "Got 0 keys from insecure file");
print "# Testing missing file, nothing should be found\n"; diag "Testing missing file, nothing should be found\n";
chmod 0644, $netrc; chmod 0644, $netrc;
$cred = run_credential(['-f', '///nosuchfile///', 'get'], $cred = run_credential(['-f', '///nosuchfile///', 'get'],
{ host => 'github.com' }); { host => 'github.com' });
ok(scalar keys %$cred, 0, "Got 0 keys from missing file"); ok(scalar keys %$cred == 0, "Got 0 keys from missing file");
chmod 0600, $netrc; chmod 0600, $netrc;
print "# Testing with invalid data\n"; diag "Testing with invalid data\n";
$cred = run_credential(['-f', $netrc, 'get'], $cred = run_credential(['-f', $netrc, 'get'],
"bad data"); "bad data");
ok(scalar keys %$cred, 4, "Got first found keys with bad data"); ok(scalar keys %$cred == 4, "Got first found keys with bad data");
print "# Testing netrc file for a missing corovamilkbar entry\n"; diag "Testing netrc file for a missing corovamilkbar entry\n";
$cred = run_credential(['-f', $netrc, 'get'], $cred = run_credential(['-f', $netrc, 'get'],
{ host => 'corovamilkbar' }); { host => 'corovamilkbar' });
ok(scalar keys %$cred, 0, "Got no corovamilkbar keys"); ok(scalar keys %$cred == 0, "Got no corovamilkbar keys");
print "# Testing netrc file for a github.com entry\n"; diag "Testing netrc file for a github.com entry\n";
$cred = run_credential(['-f', $netrc, 'get'], $cred = run_credential(['-f', $netrc, 'get'],
{ host => 'github.com' }); { host => 'github.com' });
ok(scalar keys %$cred, 2, "Got 2 Github keys"); ok(scalar keys %$cred == 2, "Got 2 Github keys");
ok($cred->{password}, 'carolknows', "Got correct Github password"); is($cred->{password}, 'carolknows', "Got correct Github password");
ok($cred->{username}, 'carol', "Got correct Github username"); is($cred->{username}, 'carol', "Got correct Github username");
print "# Testing netrc file for a username-specific entry\n"; diag "Testing netrc file for a username-specific entry\n";
$cred = run_credential(['-f', $netrc, 'get'], $cred = run_credential(['-f', $netrc, 'get'],
{ host => 'imap', username => 'bob' }); { host => 'imap', username => 'bob' });
ok(scalar keys %$cred, 2, "Got 2 username-specific keys"); ok(scalar keys %$cred == 2, "Got 2 username-specific keys");
ok($cred->{password}, 'bobwillknow', "Got correct user-specific password"); is($cred->{password}, 'bobwillknow', "Got correct user-specific password");
ok($cred->{protocol}, 'imaps', "Got correct user-specific protocol"); is($cred->{protocol}, 'imaps', "Got correct user-specific protocol");
print "# Testing netrc file for a host:port-specific entry\n"; diag "Testing netrc file for a host:port-specific entry\n";
$cred = run_credential(['-f', $netrc, 'get'], $cred = run_credential(['-f', $netrc, 'get'],
{ host => 'imap2:1099' }); { host => 'imap2:1099' });
ok(scalar keys %$cred, 2, "Got 2 host:port-specific keys"); ok(scalar keys %$cred == 2, "Got 2 host:port-specific keys");
ok($cred->{password}, 'tzzknow', "Got correct host:port-specific password"); is($cred->{password}, 'tzzknow', "Got correct host:port-specific password");
ok($cred->{username}, 'tzz', "Got correct host:port-specific username"); is($cred->{username}, 'tzz', "Got correct host:port-specific username");
print "# Testing netrc file that 'host:port kills host' entry\n"; diag "Testing netrc file that 'host:port kills host' entry\n";
$cred = run_credential(['-f', $netrc, 'get'], $cred = run_credential(['-f', $netrc, 'get'],
{ host => 'imap2' }); { host => 'imap2' });
ok(scalar keys %$cred, 2, "Got 2 'host:port kills host' keys"); ok(scalar keys %$cred == 2, "Got 2 'host:port kills host' keys");
is($cred->{password}, 'bobwillknow', "Got correct 'host:port kills host' password");
is($cred->{username}, 'bob', "Got correct 'host:port kills host' username");
diag 'Testing netrc file decryption by git config gpg.program setting\n';
$cred = run_credential( ['-f', $netrcGpg, 'get']
, { host => 'git-config-gpg' }
);
ok(scalar keys %$cred == 2, 'Got keys decrypted by git config option');
diag 'Testing netrc file decryption by gpg option\n';
$cred = run_credential( ['-f', $netrcGpg, '-g', 'test.command-option-gpg', 'get']
, { host => 'command-option-gpg' }
);
ok($cred->{password}, 'bobwillknow', "Got correct 'host:port kills host' password"); ok(scalar keys %$cred == 2, 'Got keys decrypted by command option');
ok($cred->{username}, 'bob', "Got correct 'host:port kills host' username");
sub run_credential sub run_credential
{ {
my $args = shift @_; my $args = shift @_;
my $data = shift @_; my $data = shift @_;
my $pid = open2(my $chld_out, my $chld_in, my $pid = open2(my $chld_out, my $chld_in,
'./git-credential-netrc', @global_credential_args, $gcNetrc, @global_credential_args,
@$args); @$args);
die "Couldn't open pipe to netrc credential helper: $!" unless $pid; die "Couldn't open pipe to netrc credential helper: $!" unless $pid;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册