From 878d1583017483976ac64f26b4f806a05d445cf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isma=C3=ABl=20Bouya?= Date: Thu, 14 Oct 2021 15:29:33 +0200 Subject: Bump gitolite and add new feature --- modules/private/gitolite/default.nix | 2 + overlays/default.nix | 1 + overlays/gitolite/default.nix | 8 ++ overlays/gitolite/invite | 172 +++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100644 overlays/gitolite/default.nix create mode 100755 overlays/gitolite/invite diff --git a/modules/private/gitolite/default.nix b/modules/private/gitolite/default.nix index e54ee8a..0fb1a99 100644 --- a/modules/private/gitolite/default.nix +++ b/modules/private/gitolite/default.nix @@ -70,6 +70,8 @@ in { in [ (pkgs.python3.withPackages python-packages) + pkgs.nettools + pkgs.findutils ]; # Installation: https://git.immae.eu/mantisbt/view.php?id=93 services.gitolite = { diff --git a/overlays/default.nix b/overlays/default.nix index 1f1528c..a64097c 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -19,6 +19,7 @@ in flakes // { dwm = import ./dwm; elinks = import ./elinks; gitweb = import ./gitweb; + gitolite = import ./gitolite; goaccess = import ./goaccess; kanboard = import ./kanboard; ldapvi = import ./ldapvi; diff --git a/overlays/gitolite/default.nix b/overlays/gitolite/default.nix new file mode 100644 index 0000000..7f8f007 --- /dev/null +++ b/overlays/gitolite/default.nix @@ -0,0 +1,8 @@ +self: super: { + gitolite = super.gitolite.overrideAttrs(old: { + postPatch = old.postPatch + '' + sed -i -e "s@/bin/rm@rm@" src/commands/sskm + cp ${./invite} src/commands/invite + ''; + }); +} diff --git a/overlays/gitolite/invite b/overlays/gitolite/invite new file mode 100755 index 0000000..3cc2dbd --- /dev/null +++ b/overlays/gitolite/invite @@ -0,0 +1,172 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use lib $ENV{GL_LIBDIR}; +use Gitolite::Rc; +use Gitolite::Common; + +=for usage +Please see usage at https://www.immae.eu/docs/forge-logicielle/gitolite.html#inviter-des-collaborateurs +=cut + +usage() if @ARGV and ($ARGV[0] eq '-h' or $ARGV[0] eq '--help'); + +my $rb = $rc{GL_REPO_BASE}; +my $ab = $rc{GL_ADMIN_BASE}; +# get to the keydir +_chdir("$ab/keydir"); + +# save arguments for later +my $operation = shift || 'list'; +my $invitekeyid = shift || ''; +$invitekeyid and $invitekeyid !~ /^[-0-9a-z_]+@[-0-9a-z_]+$/i and die "invalid keyid $invitekeyid\n"; +my ($invited, $keyid) = split /@/, $invitekeyid; + +# get the actual userid and keytype +my $gl_user = $ENV{GL_USER}; +die "This function is reserved for actual users" if $gl_user =~ s/-invite-(.*)$//; + +# ---- +# first collect the keys + +my ( @invited_keys ); + +for my $pubkey (`find . -type f -name "*.pub" | sort`) { + chomp($pubkey); + $pubkey =~ s(^./)(); # artifact of the find command + + my $user = $pubkey; + $user =~ s(.*/)(); # foo/bar/baz.pub -> baz.pub + $user =~ s/(\@[^.]+)?\.pub$//; # baz.pub, baz@home.pub -> baz + + if ( $user =~ m(^(zzz-marked-for-...-)?$gl_user-invite-) ) { + push @invited_keys, $pubkey; + } +} + +# ---- +# list mode; just do it and exit +sub print_keylist { + my ( $message, @list ) = @_; + return unless @list; + print "== $message ==\n"; + my $count = 1; + for (@list) { + my $fp = fingerprint($_); + s/(zzz-marked-for-...-)?$gl_user-invite-//g; + s/\.pub$//; + s(.*/)(); + print $count++ . ": $fp : $_\n"; + } +} +if ( $operation eq 'list' ) { + print "you have the following invited keys:\n"; + print_keylist( "keys for invited persons", @invited_keys ); + print "\n\n"; + exit; +} + +# ---- +# please see docs for details on how a user interacts with this + +die "valid operations: add, del\n" unless $operation =~ /^(add|del)$/; + +if ( $operation eq 'add' ) { + print STDERR "please supply the new key on STDIN. (I recommend you + don't try to do this interactively, but use a pipe)\n"; + kf_add( $gl_user, $invited, $keyid, safe_stdin() ); +} elsif ( $operation eq 'del' ) { + kf_del( $gl_user, $invited, $keyid ); +} + +exit; + +# ---- + +# make a temp clone and switch to it +our $TEMPDIR; +BEGIN { $TEMPDIR = `mktemp -d -t tmp.XXXXXXXXXX`; } +END { `rm -rf $TEMPDIR`; } + +sub cd_temp_clone { + chomp($TEMPDIR); + hushed_git( "clone", "$rb/gitolite-admin.git", "$TEMPDIR" ); + chdir($TEMPDIR); + my $hostname = `hostname`; chomp($hostname); + hushed_git( "config", "--get", "user.email" ) and hushed_git( "config", "user.email", $ENV{USER} . "@" . $hostname ); + hushed_git( "config", "--get", "user.name" ) and hushed_git( "config", "user.name", "$ENV{USER} on $hostname" ); +} + +sub fingerprint { + my ($fp, $output) = ssh_fingerprint_file(shift); + # Do not print the output of $output to an untrusted destination. + die "does not seem to be a valid pubkey\n" unless $fp; + return $fp; +} + +sub safe_stdin { + # read one line from STDIN + my $data; + my $ret = read STDIN, $data, 4096; + # current pubkeys are approx 400 bytes so we go a little overboard + die "could not read pubkey data" . ( defined($ret) ? "" : ": $!" ) . "\n" unless $ret; + die "pubkey data seems to have more than one line\n" if $data =~ /\n./; + return $data; +} + +sub hushed_git { + local (*STDOUT) = \*STDOUT; + local (*STDERR) = \*STDERR; + open( STDOUT, ">", "/dev/null" ); + open( STDERR, ">", "/dev/null" ); + system( "git", @_ ); +} + +sub highlander { + # there can be only one + my ( $keyid, $die_if_empty, @a ) = @_; + # too many? + if ( @a > 1 ) { + print STDERR " +more than one key satisfies this condition, and I can't deal with that! +The keys are: + +"; + print STDERR "\t" . join( "\n\t", @a ), "\n\n"; + exit 1; + } + # too few? + die "no keys with " . ( $keyid || "empty" ) . " keyid found\n" if $die_if_empty and not @a; + + return @a; +} + +sub kf_add { + my ( $gl_user, $invited, $keyid, $keymaterial ) = @_; + + # add a new "invited" key for $gl_user. + cd_temp_clone(); + chdir("keydir"); + + mkdir("invited"); + _print( "invited/$gl_user-invite-$invited\@$keyid.pub", $keymaterial ); + hushed_git( "add", "." ) and die "git add failed\n"; + my $fp = fingerprint("invited/$gl_user-invite-$invited\@$keyid.pub"); + hushed_git( "commit", "-m", "invite add $gl_user-invite-$invited\@$keyid ($fp)" ) and die "git commit failed\n"; + system("gitolite push >/dev/null 2>/dev/null") and die "git push failed\n"; +} + +sub kf_del { + my ( $gl_user, $invited, $keyid ) = @_; + + cd_temp_clone(); + chdir("keydir"); + + my @pk = highlander( $keyid, 1, grep { m(^(.*/)?(zzz-marked-for-...-)?$gl_user-invite-$invited\@$keyid.pub$) } @invited_keys ); + + my $fp = fingerprint( $pk[0] ); + hushed_git( "rm", $pk[0]) and die "git mv failed\n"; + hushed_git( "commit", "-m", "invite del $pk[0] ($fp)" ) and die "git commit failed\n"; + system("gitolite push >/dev/null 2>/dev/null") and die "git push failed\n"; +} -- cgit v1.2.3