From: Ted Zlatanov <tzz@lifelogs.com>
To: Junio C Hamano <gitster@pobox.com>
Cc: Jeff King <peff@peff.net>, git@vger.kernel.org
Subject: [PATCHv3] Add contrib/credentials/netrc with GPG support
Date: Mon, 04 Feb 2013 18:28:26 -0500 [thread overview]
Message-ID: <87fw1bslph.fsf_-_@lifelogs.com> (raw)
In-Reply-To: <7vd2wf1yex.fsf@alter.siamese.dyndns.org> (Junio C. Hamano's message of "Mon, 04 Feb 2013 14:56:06 -0800")
Changes since PATCHv2:
- don't keep looking at netrc candidates if one good one is found
- fixed wording of "line" to "entry" everywhere suitable
- many (but not all) statement modifiers changed to block format
- use -r everywhere instead of -f
- move chomp to when we know @data has contents
Signed-off-by: Ted Zlatanov <tzz@lifelogs.com>
---
contrib/credential/netrc/git-credential-netrc | 243 +++++++++++++++++++++++++
1 files changed, 243 insertions(+), 0 deletions(-)
create mode 100755 contrib/credential/netrc/git-credential-netrc
diff --git a/contrib/credential/netrc/git-credential-netrc b/contrib/credential/netrc/git-credential-netrc
new file mode 100755
index 0000000..99ab204
--- /dev/null
+++ b/contrib/credential/netrc/git-credential-netrc
@@ -0,0 +1,243 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+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',
+ }
+ );
+
+# map each credential protocol token to itself on the netrc side
+foreach (values %{$options{tmap}}) {
+ $options{tmap}->{$_} = $_;
+}
+
+FILE:
+foreach my $suffix ('.gpg', '') {
+ foreach my $base (qw/authinfo netrc/) {
+ my $file = glob("~/.$base$suffix");
+ next unless (defined $file && -r $file);
+ $options{file} = $file;
+ last 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: BSD.
+
+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 this query on STDIN:
+
+protocol=https
+username=tzz
+
+this credential helper will look for entries 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 entry,
+including "password" tokens, mapping e.g. "port" back to "protocol".
+
+The first matching entry 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};
+
+unless (defined $file) {
+ print STDERR "Please specify an existing netrc file (with or without a .gpg extension) with -f AUTHFILE\n" if $debug;
+ exit 0;
+}
+
+unless (-r $file) {
+ print STDERR "Sorry, the specified netrc $file is not accessible\n" if $debug;
+ exit 0;
+}
+
+my @data;
+if ($file =~ m/\.gpg$/) {
+ @data = load('-|', qw(gpg --decrypt), $file)
+}
+else {
+ @data = load('<', $file);
+}
+
+unless (scalar @data) {
+ print STDERR "Sorry, we could not load data from [$file]\n" if $debug;
+ exit;
+}
+
+chomp @data;
+
+# the query: start with every token with no value
+my %q = map { $_ => undef } values(%{$options{tmap}});
+
+while (<STDIN>) {
+ next unless m/^([^=]+)=(.+)/;
+
+ 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);
+ }
+
+ # skip blank lines, comments, etc.
+ next LINE unless scalar @tok;
+
+ my %tokens;
+ my $num_port;
+ while (@tok) {
+ my ($k, $v) = (shift @tok, shift @tok);
+ next unless defined $v;
+ next unless exists $options{tmap}->{$k};
+ $tokens{$options{tmap}->{$k}} = $v;
+ $num_port = ($k eq 'port' && $v =~ m/^\d+$/) ? $v : undef;
+ }
+
+ # for "host X port Y" where Y is an integer (captured by
+ # $num_port above), set the host to "X:Y"
+ if (defined $tokens{host} && defined $num_port) {
+ $tokens{host} = join(':', $tokens{host}, $num_port);
+ }
+
+ foreach my $check (sort keys %q) {
+ if (exists $tokens{$check} && defined $q{$check}) {
+ print STDERR "comparing [$tokens{$check}] to [$q{$check}] in entry [$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 "entry has passed all the search checks\n" if $debug;
+ TOKEN:
+ 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}}) {
+ # don't re-print given tokens
+ next TOKEN if defined $q{$rctoken};
+ }
+
+ print STDERR "FOUND: $token=$tokens{$token}\n" if $debug;
+ printf "%s=%s\n", $token, $tokens{$token};
+ }
+
+ last;
+}
+
+sub load {
+ # this supports pipes too
+ my $io = new IO::File(@_) or die "Could not open [@_]: $!\n";
+ return <$io>; # whole file
+}
--
1.7.9.rc2
next prev parent reply other threads:[~2013-02-04 23:29 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-02-04 19:54 [PATCH] Add contrib/credentials/netrc with GPG support Ted Zlatanov
2013-02-04 21:17 ` Jeff King
2013-02-04 21:32 ` Ted Zlatanov
2013-02-04 21:44 ` [PATCH] Add contrib/credentials/netrc with GPG support, try #2 Ted Zlatanov
2013-02-04 22:56 ` Junio C Hamano
2013-02-04 23:23 ` Jeff King
2013-02-04 23:36 ` Junio C Hamano
2013-02-04 23:42 ` Ted Zlatanov
2013-02-04 23:28 ` Ted Zlatanov [this message]
2013-02-04 23:31 ` Ted Zlatanov
2013-02-04 23:40 ` Junio C Hamano
2013-02-04 23:54 ` Ted Zlatanov
2013-02-05 0:15 ` Junio C Hamano
2013-02-05 13:39 ` Ted Zlatanov
2013-02-05 16:07 ` Junio C Hamano
2013-02-05 16:18 ` Junio C Hamano
2013-02-05 16:15 ` Junio C Hamano
2013-02-05 17:01 ` Ted Zlatanov
2013-02-05 18:55 ` [PATCHv4] Add contrib/credentials/netrc with GPG support Ted Zlatanov
2013-02-05 19:53 ` Junio C Hamano
2013-02-05 20:47 ` Ted Zlatanov
2013-02-05 22:09 ` Junio C Hamano
2013-02-05 22:30 ` Ted Zlatanov
2013-02-05 20:55 ` [PATCHv5] " Ted Zlatanov
2013-02-05 22:24 ` Junio C Hamano
2013-02-05 23:58 ` Junio C Hamano
2013-02-06 0:38 ` [PATCHv6] " Ted Zlatanov
2013-02-07 23:52 ` Junio C Hamano
2013-02-08 1:53 ` Ted Zlatanov
2013-02-08 6:15 ` Junio C Hamano
2013-02-08 6:18 ` Jeff King
2013-02-25 16:24 ` Ted Zlatanov
2013-02-25 15:49 ` [PATCH v7] " Ted Zlatanov
2013-02-06 0:34 ` [PATCHv5] " Ted Zlatanov
2013-02-05 19:47 ` [PATCH] Add contrib/credentials/netrc with GPG support, try #2 Junio C Hamano
2013-02-05 20:03 ` Ted Zlatanov
2013-02-05 20:23 ` Junio C Hamano
2013-02-05 21:00 ` Ted Zlatanov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87fw1bslph.fsf_-_@lifelogs.com \
--to=tzz@lifelogs.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=peff@peff.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).