All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.