[PATCHv4] Add contrib/credentials/netrc with GPG support

2013-02-05 Thread Ted Zlatanov
Changes since PATCHv3:

- simple tests in Makefile
- support multiple files, code refactored
- documentation and comments updated
- fix IO::File for GPG pipe
- exit peacefully in almost every situation, die on bad invocation or query
- use log_verbose() and -v for logging for the user
- use log_debug() and -d for logging for the developer
- use Net::Netrc parser and `man netrc' to improve parsing
- ignore 'default' and 'macdef' netrc entries
- require 'machine' token in netrc lines
- ignore netrc files with bad permissions or owner (from Net::Netrc)

Signed-off-by: Ted Zlatanov t...@lifelogs.com
---
 contrib/credential/netrc/Makefile |   10 +
 contrib/credential/netrc/git-credential-netrc |  423 +
 2 files changed, 433 insertions(+), 0 deletions(-)
 create mode 100644 contrib/credential/netrc/Makefile
 create mode 100755 contrib/credential/netrc/git-credential-netrc

diff --git a/contrib/credential/netrc/Makefile 
b/contrib/credential/netrc/Makefile
new file mode 100644
index 000..ee8c5f0
--- /dev/null
+++ b/contrib/credential/netrc/Makefile
@@ -0,0 +1,10 @@
+test_netrc:
+   @(echo bad data | ./git-credential-netrc -f A -d -v) || echo Bad 
invocation test, ignoring failure
+   @echo - Silent invocation... nothing should show up here with a 
missing file
+   @echo bad data | ./git-credential-netrc -f A get
+   @echo - Back to noisy: -v and -d used below, missing file
+   echo bad data | ./git-credential-netrc -f A -d -v get
+   @echo - Look for any entry in the default file set
+   echo  | ./git-credential-netrc -d -v get
+   @echo - Look for github.com in the default file set
+   echo host=google.com | ./git-credential-netrc -d -v get
diff --git a/contrib/credential/netrc/git-credential-netrc 
b/contrib/credential/netrc/git-credential-netrc
new file mode 100755
index 000..6946217
--- /dev/null
+++ b/contrib/credential/netrc/git-credential-netrc
@@ -0,0 +1,423 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Getopt::Long;
+use File::Basename;
+
+my $VERSION = 0.1;
+
+my %options = (
+   help = 0,
+   debug = 0,
+   verbose = 0,
+  file = [],
+
+   # identical token maps, e.g. host - host, will be inserted 
later
+   tmap = {
+port = 'protocol',
+machine = 'host',
+path = 'path',
+login = 'username',
+user = 'username',
+password = 'password',
+   }
+  );
+
+# Map each credential protocol token to itself on the netrc side.
+foreach (values %{$options{tmap}}) {
+   $options{tmap}-{$_} = $_;
+}
+
+# Now, $options{tmap} has a mapping from the netrc format to the Git credential
+# helper protocol.
+
+# Next, we build the reverse token map.
+
+# When $rmap{foo} contains 'bar', that means that what the Git credential 
helper
+# protocol calls 'bar' is found as 'foo' in the netrc/authinfo file.  Keys in
+# %rmap are what we expect to read from the netrc/authinfo file.
+
+my %rmap;
+foreach my $k (keys %{$options{tmap}}) {
+   push @{$rmap{$options{tmap}-{$k}}}, $k;
+}
+
+Getopt::Long::Configure(bundling);
+
+# TODO: maybe allow the token map $options{tmap} to be configurable.
+GetOptions(\%options,
+   help|h,
+   debug|d,
+   verbose|v,
+   file|f=s@,
+  );
+
+if ($options{help}) {
+   my $shortname = basename($0);
+   $shortname =~ s/git-credential-//;
+
+   print EOHIPPUS;
+
+$0 [-f AUTHFILE1] [-f AUTHFILEN] [-d] [-v] get
+
+Version $VERSION by tzz\@lifelogs.com.  License: BSD.
+
+Options:
+
+  -f|--file AUTHFILE : specify netrc-style files.  Files with the .gpg 
extension
+   will be decrypted by GPG before parsing.  Multiple -f
+   arguments are OK, and the order is respected.
+
+  -d|--debug : turn on debugging (developer info)
+
+  -v|--verbose   : be more verbose (show files and information found)
+
+To enable this credential helper:
+
+  git config credential.helper '$shortname -f AUTHFILE1 -f AUTHFILE2'
+
+(Note that Git will prepend git-credential- to the helper name and look for 
it
+in the path.)
+
+...and if you want lots of debugging info:
+
+  git config credential.helper '$shortname -f AUTHFILE -d'
+
+...or to see the files opened and data found:
+
+  git config credential.helper '$shortname -f AUTHFILE -v'
+
+Only get mode is supported by this credential helper.  It opens every 
AUTHFILE
+and looks for the first entry that matches the requested search criteria:
+
+ 'port|protocol':
+   The protocol that will be used (e.g., https). (protocol=X)
+
+ 'machine|host':
+   The remote hostname for a network credential. (host=X)
+
+ 'path':
+   The path with which the credential will be used. (path=X)
+
+ 'login|user|username':
+   The credential’s username, if we 

Re: [PATCHv4] Add contrib/credentials/netrc with GPG support

2013-02-05 Thread Junio C Hamano
Ted Zlatanov t...@lifelogs.com writes:

 Changes since PATCHv3:

 - simple tests in Makefile
 - support multiple files, code refactored
 - documentation and comments updated
 - fix IO::File for GPG pipe
 - exit peacefully in almost every situation, die on bad invocation or query
 - use log_verbose() and -v for logging for the user
 - use log_debug() and -d for logging for the developer
 - use Net::Netrc parser and `man netrc' to improve parsing
 - ignore 'default' and 'macdef' netrc entries
 - require 'machine' token in netrc lines
 - ignore netrc files with bad permissions or owner (from Net::Netrc)

Please place the above _after_ the three-dashes.

The space here, above ---, is to justify why this change is a good
idea to people who see this patch for the first time who never saw
the earlier rounds of this patch, e.g. reading git log output 6
months down the road (see Documentation/SubmittingPatches (2)
Describe your changes well).


 Signed-off-by: Ted Zlatanov t...@lifelogs.com
 ---
  contrib/credential/netrc/Makefile |   10 +
  contrib/credential/netrc/git-credential-netrc |  423 
 +
  2 files changed, 433 insertions(+), 0 deletions(-)
  create mode 100644 contrib/credential/netrc/Makefile
  create mode 100755 contrib/credential/netrc/git-credential-netrc

 diff --git a/contrib/credential/netrc/Makefile 
 b/contrib/credential/netrc/Makefile
 new file mode 100644
 index 000..ee8c5f0
 --- /dev/null
 +++ b/contrib/credential/netrc/Makefile
 @@ -0,0 +1,10 @@
 +test_netrc:
 + @(echo bad data | ./git-credential-netrc -f A -d -v) || echo Bad 
 invocation test, ignoring failure
 + @echo - Silent invocation... nothing should show up here with a 
 missing file

Avoid starting an argument to echo with a dash; some
implementations choke with unknown option.

 + @echo bad data | ./git-credential-netrc -f A get
 + @echo - Back to noisy: -v and -d used below, missing file
 + echo bad data | ./git-credential-netrc -f A -d -v get
 + @echo - Look for any entry in the default file set
 + echo  | ./git-credential-netrc -d -v get
 + @echo - Look for github.com in the default file set
 + echo host=google.com | ./git-credential-netrc -d -v get
 diff --git a/contrib/credential/netrc/git-credential-netrc 
 b/contrib/credential/netrc/git-credential-netrc
 new file mode 100755
 index 000..6946217
 --- /dev/null
 +++ b/contrib/credential/netrc/git-credential-netrc
 @@ -0,0 +1,423 @@
 +#!/usr/bin/perl
 +
 +use strict;
 +use warnings;
 +
 +use Getopt::Long;
 +use File::Basename;
 +
 +my $VERSION = 0.1;
 +
 +my %options = (
 +   help = 0,
 +   debug = 0,
 +   verbose = 0,
 +file = [],

Looks like there is some funny indentation going on here.

 +
 +   # identical token maps, e.g. host - host, will be inserted 
 later
 +   tmap = {
 +port = 'protocol',
 +machine = 'host',
 +path = 'path',
 +login = 'username',
 +user = 'username',
 +password = 'password',
 +   }
 +  );
 +
 +# Map each credential protocol token to itself on the netrc side.
 +foreach (values %{$options{tmap}}) {
 + $options{tmap}-{$_} = $_;
 +}
 +
 +# Now, $options{tmap} has a mapping from the netrc format to the Git 
 credential
 +# helper protocol.
 +
 +# Next, we build the reverse token map.
 +
 +# When $rmap{foo} contains 'bar', that means that what the Git credential 
 helper
 +# protocol calls 'bar' is found as 'foo' in the netrc/authinfo file.  Keys in
 +# %rmap are what we expect to read from the netrc/authinfo file.
 +
 +my %rmap;
 +foreach my $k (keys %{$options{tmap}}) {
 + push @{$rmap{$options{tmap}-{$k}}}, $k;
 +}
 +
 +Getopt::Long::Configure(bundling);
 +
 +# TODO: maybe allow the token map $options{tmap} to be configurable.
 +GetOptions(\%options,
 +   help|h,
 +   debug|d,
 +   verbose|v,
 +   file|f=s@,
 +  );
 +
 +if ($options{help}) {
 + my $shortname = basename($0);
 + $shortname =~ s/git-credential-//;
 +
 + print EOHIPPUS;
 +
 +$0 [-f AUTHFILE1] [-f AUTHFILEN] [-d] [-v] get
 +
 +Version $VERSION by tzz\@lifelogs.com.  License: BSD.
 +
 +Options:
 +
 +  -f|--file AUTHFILE : specify netrc-style files.  Files with the .gpg 
 extension
 +   will be decrypted by GPG before parsing.  Multiple -f
 +   arguments are OK, and the order is respected.

Saying order is respected without mentioning the collision
resolution rules is not helpful to the users when deciding in what
order they should give these files.  First one wins, or last one
wins?  Later you say looks for the first entry, but it will be
much easier to read the above to mention it here as well.

 +  -d|--debug : turn on debugging (developer info)
 +
 +  

Re: [PATCHv4] Add contrib/credentials/netrc with GPG support

2013-02-05 Thread Ted Zlatanov
On Tue, 05 Feb 2013 11:53:20 -0800 Junio C Hamano gits...@pobox.com wrote: 

JCH Ted Zlatanov t...@lifelogs.com writes:
 Changes since PATCHv3:
 
 - simple tests in Makefile
 - support multiple files, code refactored
 - documentation and comments updated
 - fix IO::File for GPG pipe
 - exit peacefully in almost every situation, die on bad invocation or query
 - use log_verbose() and -v for logging for the user
 - use log_debug() and -d for logging for the developer
 - use Net::Netrc parser and `man netrc' to improve parsing
 - ignore 'default' and 'macdef' netrc entries
 - require 'machine' token in netrc lines
 - ignore netrc files with bad permissions or owner (from Net::Netrc)

JCH Please place the above _after_ the three-dashes.

JCH The space here, above ---, is to justify why this change is a good
JCH idea to people who see this patch for the first time who never saw
JCH the earlier rounds of this patch, e.g. reading git log output 6
JCH months down the road (see Documentation/SubmittingPatches (2)
JCH Describe your changes well).

Will do in PATCHv5.

JCH Avoid starting an argument to echo with a dash; some
JCH implementations choke with unknown option.

Nice, thanks.  It's purely decorative so I use '=' now.

 +my %options = (
 +   help = 0,
 +   debug = 0,
 +   verbose = 0,
 +   file = [],

JCH Looks like there is some funny indentation going on here.

Fixed.

 +  -f|--file AUTHFILE : specify netrc-style files.  Files with the .gpg 
 extension
 +   will be decrypted by GPG before parsing.  Multiple -f
 +   arguments are OK, and the order is respected.

JCH Saying order is respected without mentioning the collision
JCH resolution rules is not helpful to the users when deciding in what
JCH order they should give these files.  First one wins, or last one
JCH wins?  Later you say looks for the first entry, but it will be
JCH much easier to read the above to mention it here as well.

Right.  Reworded.

 +Thus, when we get this query on STDIN:
 +
 +protocol=https
 +username=tzz
 +
 +this credential helper will look for the first entry in every AUTHFILE that
 +matches
 +
 +port https login tzz
 +
 +OR
 +
 +protocol https login tzz
 +
 +OR... etc. acceptable tokens as listed above.  Any unknown tokens are
 +simply ignored.
 +
 +Then, the helper will print out whatever tokens it got from the entry, 
 including
 +password tokens, mapping back to Git's helper protocol; e.g. port is 
 mapped
 +back to protocol.

JCH Isn't hostname typically what users expect to see?  It is somewhat
JCH unnerving to see an example that throws the same password back to
JCH any host you happen to have an accoutn tzz on, even though that is
JCH not technically an invalid way to use this helper.

Yeah, I changed it to show machine in the query (which would be more typical).

 +if ($stat[2]  077) {
 +log_verbose(Insecure $file (mode=%04o); 
 skipping it,
 +$stat[2]  0);

JCH Nice touch, although I am not sure rejecting world or group readable
JCH encrypted file is absolutely necessary.

Right.  Fixed.

 +if ($stat[4] != $) {
 +log_verbose(Not owner of $file; skipping it);
 +next FILE;

JCH OK.  A group of local users may share the same account at the
JCH remote, but that would be unusual.

I added --insecure/-k to override this check.

 +if ($mode  077)

JCH Again?  Didn't you just do this?

Damn, sorry.

JCH I think the prevalent style is to

JCHif (condition) {
JCHdo this;
JCH} elsif (another condition) {
JCHdo that
JCH} else {
JCHdo that other thing;
JCH}

JCH (this comment applies to all if/elsif/else cascades in this patch).

Yup.  I was working with Net::Netrc code and forgot to reformat it.  Sorry.

 +
 +next FILE;

JCH Isn't this outermost loop, by the way?  What the motivation to have
JCH an explicit label everywhere (not complaining---it could be your own
JCH discipline thing---just wondering).

I think it's more readable with large loops, and it actually makes sense
when you read the code.  Not a big deal to me either, I just felt for
this particular script it was OK.

 +if ($file =~ m/\.gpg$/) {
 +log_verbose(Using GPG to open $file);
 +# GPG doesn't work well with 2- or 3-argument open

JCH If that is the case, please quote $file properly against shell
JCH munging it.

Ahhh that gets ugly.  OK, quoted.

JCH The only thing you do on $io is to read from it via while ($io),
JCH so I would personally have written this part like this without
JCH having to use IO::File(), though:

JCH$io = open(-|, qw(gpg --decrypt), $file);

That doesn't work for me, unfortunately.  I'm trying to avoid the IPC::*
modules and such.  Please test it yourself with GPG.  I'm on Perl
5.14.2.

I think 

Re: [PATCHv4] Add contrib/credentials/netrc with GPG support

2013-02-05 Thread Junio C Hamano
Ted Zlatanov t...@lifelogs.com writes:

 On Tue, 05 Feb 2013 11:53:20 -0800 Junio C Hamano gits...@pobox.com wrote: 

 I think it's more readable with large loops, and it actually makes sense
 when you read the code.  Not a big deal to me either, I just felt for
 this particular script it was OK.

 +   if ($file =~ m/\.gpg$/) {
 +   log_verbose(Using GPG to open $file);
 +   # GPG doesn't work well with 2- or 3-argument open

 JCH If that is the case, please quote $file properly against shell
 JCH munging it.

 Ahhh that gets ugly.  OK, quoted.

 JCH The only thing you do on $io is to read from it via while ($io),
 JCH so I would personally have written this part like this without
 JCH having to use IO::File(), though:

 JCH  $io = open(-|, qw(gpg --decrypt), $file);

 That doesn't work for me, unfortunately.  I'm trying to avoid the IPC::*
 modules and such.  Please test it yourself with GPG.  I'm on Perl
 5.14.2.

This works for me as expected (sorry for that open $io syntax
gotcha).

-- cut here -- 8 -- cut here --

#!/usr/bin/perl
my $io;
open $io, -|, qw(gpg --decrypt), $ARGV[0]
or die $!: gpg open;
while ($io) {
print;
}
close $io
or die $!: gpg close;

-- cut here -- 8 -- cut here --

$ perl --version
This is perl, v5.10.1 (*) built for x86_64-linux-gnu-thread-multi
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html