git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] git-send-email: add ~/.authinfo parsing

From
Ted Zlatanov <tzz@lifelogs.com>
Date
Feb 2, 2013, 11:57 UTC
Message-ID
<87k3qrx712.fsf@lifelogs.com>
In-Reply-To
<20130131193844.GA14460@sigill.intra.peff.net>
On Thu, 31 Jan 2013 14:38:45 -0500 Jeff King <peff@peff.net> wrote: 
JK> On Thu, Jan 31, 2013 at 10:23:51AM -0500, Ted Zlatanov wrote:
Show 7 quoted lines
>> Jeff, is there a way for git-credential to currently support
>> authinfo/netrc parsing?  I assume that's the right way, instead of using
>> Michal's proposal to parse internally?
>> 
>> I'd like to add that, plus support for the 'string' and "string"
>> formats, and authinfo.gpg decoding through GPG.  I'd write it in Perl,
>> if there's a choice.

JK> Yes, you could write a credential helper that understands netrc and JK> friends; git talks to the helpers over a socket, so there is no problem JK> with writing it in Perl. See Documentation/technical/api-credentials.txt JK> for an overview, or the sample implementation in credential-store.c for a JK> simple example.

I wrote a Perl credential helper for netrc parsing which is pretty robust, has built-in docs with -h, and doesn't depend on external modules. The netrc parser regex was stolen from Net::Netrc.

It will by default use ~/.authinfo.gpg, ~/.netrc.gpg, ~/.authinfo, and ~/.netrc (whichever is found first) and this can be overridden with -f.

If the file name ends with ".gpg", it will run "gpg --decrypt FILE" and use the output. So non-interactively, that could hang if GPG was waiting for input. Does Git handle that, or should I check for a TTY?

Take a look at the proposed patch and let me know if it's usable, if you need a formal copyright assignment, etc.

Thanks Ted

commit 3d28bc2a610ebcc988eba5443d82d0ded92c24bc
Author: Ted Zlatanov <tzz@lifelogs.com>
Date:   Sat Feb 2 06:42:13 2013 -0500
    Add contrib/credentials/netrc with GPG support
diff --git a/contrib/credential/netrc/git-credential-netrc b/contrib/credential/netrc/git-credential-netrc
new file mode 100755
index 0000000..92fc306
--- /dev/null
+++ b/contrib/credential/netrc/git-credential-netrc
@@ -0,0 +1,242 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Data::Dumper;
+
+use Getopt::Long;
+use File::Basename;
+
+my $VERSION = "0.1";
+
+my %options = (
+               help => 0,
+               debug => 0,
+
+               # identical token maps, e.g. host -> host, will be inserted later
+               tmap => {
+                        port => 'protocol',
+                        machine => 'host',
+                        path => 'path',
+                        login => 'username',
+                        user => 'username',
+                        password => 'password',
+                       }
+              );
+
+foreach my $v (values %{$options{tmap}})
+{
+ $options{tmap}->{$v} = $v;
+}
+
+foreach my $suffix ('.gpg', '')
+{
+ foreach my $base (qw/authinfo netrc/)
+ {
+  my $file = glob("~/.$base$suffix");
+  next unless (defined $file && -f $file);
+  $options{file} = $file ;
+ }
+}
+
+Getopt::Long::Configure("bundling");
+
+# TODO: maybe allow the token map $options{tmap} to be configurable.
+GetOptions(\%options,
+           "help|h",
+           "debug|d",
+           "file|f=s",
+          );
+
+if ($options{help})
+{
+ my $shortname = basename($0);
+ $shortname =~ s/git-credential-//;
+
+ print <<EOHIPPUS;
+
+$0 [-f AUTHFILE] [-d] get
+
+Version $VERSION by tzz\@lifelogs.com.  License: any use is OK.
+
+Options:
+  -f AUTHFILE: specify a netrc-style file
+  -d: turn on debugging
+
+To enable (note that Git will prepend "git-credential-" to the helper
+name and look for it in the path):
+
+  git config credential.helper '$shortname -f AUTHFILE'
+
+And if you want lots of debugging info:
+
+  git config credential.helper '$shortname -f AUTHFILE -d'
+
+Only "get" mode is supported by this credential helper.  It opens
+AUTHFILE and looks for entries that match 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 already have one. (username=X)
+
+Thus, when we get "protocol=https\nusername=tzz", this credential
+helper will look for lines in AUTHFILE that match
+
+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 line,
+including "password" tokens, mapping e.g. "port" back to "protocol".
+
+The first matching line is used.  Tokens can be quoted as 'STRING' or
+"STRING".
+
+No caching is performed by this credential helper.
+
+EOHIPPUS
+
+ exit;
+}
+
+my $mode = shift @ARGV;
+
+# credentials may get 'get', 'store', or 'erase' as parameters but
+# only acknowledge 'get'
+die "Syntax: $0 [-f AUTHFILE] [-d] get" unless defined $mode;
+
+# only support 'get' mode
+exit unless $mode eq 'get';
+
+my $debug = $options{debug};
+my $file = $options{file};
+
+die "Sorry, you need to specify an existing netrc file (with or without a .gpg extension) with -f AUTHFILE"
+ unless defined $file;
+
+die "Sorry, the specified netrc $file is not accessible"
+ unless -f $file;
+
+if ($file =~ m/\.gpg$/)
+{
+ $file = "gpg --decrypt $file|";
+}
+
+my @data = load($file);
+chomp @data;
+
+die "Sorry, we could not load data from [$file]"
+ unless (scalar @data);
+
+# the query
+my %q;
+
+foreach my $v (values %{$options{tmap}})
+{
+ undef $q{$v};
+}
+
+while (<STDIN>)
+{
+ next unless m/([a-z]+)=(.+)/;
+
+ my ($token, $value) = ($1, $2);
+ die "Unknown search token $1" unless exists $q{$token};
+ $q{$token} = $value;
+}
+
+# build reverse token map
+my %rmap;
+foreach my $k (keys %{$options{tmap}})
+{
+ push @{$rmap{$options{tmap}->{$k}}}, $k;
+}
+
+# there are CPAN modules to do this better, but we want to avoid
+# dependencies and generally, complex netrc-style files are rare
+
+if ($debug)
+{
+ foreach (sort keys %q)
+ {
+  printf STDERR "searching for %s = %s\n",
+   $_, $q{$_} || '(any value)';
+ }
+}
+
+LINE: foreach my $line (@data)
+{
+
+ print STDERR "line [$line]\n" if $debug;
+ my @tok;
+ # gratefully stolen from Net::Netrc
+ while (length $line &&
+        $line =~ s/^("((?:[^"]+|\\.)*)"|((?:[^\\\s]+|\\.)*))\s*//)
+ {
+  (my $tok = $+) =~ s/\\(.)/$1/g;
+  push(@tok, $tok);
+ }
+
+ my %tokens;
+ while (@tok)
+ {
+  my ($k, $v) = (shift @tok, shift @tok);
+  next unless defined $v;
+  next unless exists $options{tmap}->{$k};
+  $tokens{$options{tmap}->{$k}} = $v;
+ }
+
+ foreach my $check (sort keys %q)
+ {
+  if (exists $tokens{$check} && defined $q{$check})
+  {
+   print STDERR "comparing [$tokens{$check}] to [$q{$check}] in line [$line]\n" if $debug;
+   next LINE unless $tokens{$check} eq $q{$check};
+  }
+  else
+  {
+   print STDERR "we could not find [$check] but it's OK\n" if $debug;
+  }
+ }
+
+ print STDERR "line has passed all the search checks\n" if $debug;
+ foreach my $token (sort keys %rmap)
+ {
+  print STDERR "looking for useful token $token\n" if $debug;
+  next unless exists $tokens{$token}; # did we match?
+
+  foreach my $rctoken (@{$rmap{$token}})
+  {
+   next if defined $q{$rctoken};           # don't re-print given tokens
+  }
+
+  print STDERR "FOUND: $token=$tokens{$token}\n" if $debug;
+  printf "%s=%s\n", $token, $tokens{$token};
+ }
+
+ last;
+}
+
+sub load
+{
+ my $file = shift;
+ # this supports pipes too
+ my $io = new IO::File($file) or die "Could not open $file: $!\n";
+
+ return <$io>;                          # whole file
+}
Previous: Jeff KingNext: Jeff King
Message 11 of 78 in “git-send-email: add ~/.authinfo parsing”
  1. git-send-email: add ~/.authinfo parsingMichal Nazarewicz, Jan 29, 2013
  2. Junio C HamanoJan 29, 2013
  3. [PATCHv2] git-send-email: add ~/.authinfo parsingMichal Nazarewicz, Jan 29, 2013
  4. Junio C HamanoJan 29, 2013
  5. [PATCHv3] git-send-email: add ~/.authinfo parsingMichal Nazarewicz, Jan 30, 2013
  6. Junio C HamanoJan 30, 2013
  7. Jeff KingJan 30, 2013
  8. Junio C HamanoJan 30, 2013
  9. Ted ZlatanovJan 31, 2013
  10. Jeff KingJan 31, 2013
  11. Ted ZlatanovFeb 2, 2013
  12. Jeff KingFeb 3, 2013
  13. Ted ZlatanovFeb 4, 2013
  14. 1/3 Add contrib/credentials/netrc with GPG supportTed Zlatanov, Feb 4, 2013
  15. Ted ZlatanovFeb 4, 2013
  16. Junio C HamanoFeb 4, 2013
  17. Ted ZlatanovFeb 4, 2013
  18. Junio C HamanoFeb 4, 2013
  19. Ted ZlatanovFeb 4, 2013
  20. Junio C HamanoFeb 4, 2013
  21. CodingGuidelines Perl amendment (was: [PATCH 1/3] Add contrib/credentials/netrc with GPG support)Ted Zlatanov, Feb 6, 2013
  22. Junio C HamanoFeb 6, 2013
  23. demerphqFeb 6, 2013
  24. Ted ZlatanovFeb 6, 2013
  25. Junio C HamanoFeb 6, 2013
  26. demerphqFeb 6, 2013
  27. Update CodingGuidelines for Perl 5Ted Zlatanov, Feb 6, 2013
  28. Ted ZlatanovFeb 6, 2013
  29. Junio C HamanoFeb 6, 2013
  30. Ted ZlatanovFeb 6, 2013
  31. demerphqFeb 6, 2013
  32. Ted ZlatanovFeb 6, 2013
  33. demerphqFeb 6, 2013
  34. Ted ZlatanovFeb 6, 2013
  35. Junio C HamanoFeb 6, 2013
  36. Update CodingGuidelines for Perl 5Ted Zlatanov, Feb 6, 2013
  37. 2/3 Skip blank and commented lines in contrib/credentials/netrcTed Zlatanov, Feb 4, 2013
  38. 3/3 Fix contrib/credentials/netrc minor issues: exit quietly; use 3-parameter open; etc.Ted Zlatanov, Feb 4, 2013
  39. Junio C HamanoFeb 4, 2013
  40. Ted ZlatanovFeb 4, 2013
  41. Michal NazarewiczFeb 4, 2013
  42. Ted ZlatanovFeb 4, 2013
  43. Jeff KingFeb 4, 2013
  44. Ted ZlatanovFeb 4, 2013
  45. Jeff KingFeb 4, 2013
  46. Ted ZlatanovFeb 4, 2013
  47. Jeff KingFeb 4, 2013
  48. Ted ZlatanovFeb 4, 2013
  49. Junio C HamanoFeb 5, 2013
  50. Matthieu MoyFeb 6, 2013
  51. Ted ZlatanovFeb 6, 2013
  52. Matthieu MoyFeb 6, 2013
  53. Ted ZlatanovFeb 6, 2013
  54. Matthieu MoyFeb 6, 2013
  55. Ted ZlatanovFeb 6, 2013
  56. 0/4 Allow contrib/ to use Git's Makefile for perl codeMatthieu Moy, Feb 6, 2013
  57. 1/4 Makefile: extract perl-related rules to make them available from other dirsMatthieu Moy, Feb 6, 2013
  58. Junio C HamanoFeb 7, 2013
  59. 2/4 perl.mak: introduce $(GIT_ROOT_DIR) to allow inclusion from other directoriesMatthieu Moy, Feb 6, 2013
  60. 3/4 Makefile: factor common configuration in git-default-config.makMatthieu Moy, Feb 6, 2013
  61. Junio C HamanoFeb 7, 2013
  62. Matthieu MoyFeb 8, 2013
  63. 1/2 Makefile: make script-related rules usable from subdirectoriesMatthieu Moy, Feb 8, 2013
  64. 2/2 git-remote-mediawiki: use toplevel's MakefileMatthieu Moy, Feb 8, 2013
  65. 4/4 git-remote-mediawiki: use Git's Makefile to build the scriptMatthieu Moy, Feb 6, 2013
  66. Junio C HamanoFeb 7, 2013
  67. Jeff KingFeb 8, 2013
  68. Matthieu MoyFeb 8, 2013
  69. Jeff KingFeb 8, 2013
  70. Junio C HamanoFeb 8, 2013
  71. Jeff KingFeb 8, 2013
  72. Jeff KingFeb 6, 2013
  73. Ted ZlatanovFeb 6, 2013
  74. Matthieu MoyFeb 7, 2013
  75. Ted ZlatanovFeb 7, 2013
  76. Michal NazarewiczFeb 6, 2013
  77. Ted ZlatanovFeb 6, 2013
  78. Ted ZlatanovJan 30, 2013

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.