aboutsummaryrefslogtreecommitdiff
path: root/flakes/mypackages/overlays/gitolite/invite
diff options
context:
space:
mode:
Diffstat (limited to 'flakes/mypackages/overlays/gitolite/invite')
-rwxr-xr-xflakes/mypackages/overlays/gitolite/invite172
1 files changed, 172 insertions, 0 deletions
diff --git a/flakes/mypackages/overlays/gitolite/invite b/flakes/mypackages/overlays/gitolite/invite
new file mode 100755
index 0000000..3cc2dbd
--- /dev/null
+++ b/flakes/mypackages/overlays/gitolite/invite
@@ -0,0 +1,172 @@
1#!/usr/bin/perl
2use strict;
3use warnings;
4
5use lib $ENV{GL_LIBDIR};
6use Gitolite::Rc;
7use Gitolite::Common;
8
9=for usage
10Please see usage at https://www.immae.eu/docs/forge-logicielle/gitolite.html#inviter-des-collaborateurs
11=cut
12
13usage() if @ARGV and ($ARGV[0] eq '-h' or $ARGV[0] eq '--help');
14
15my $rb = $rc{GL_REPO_BASE};
16my $ab = $rc{GL_ADMIN_BASE};
17# get to the keydir
18_chdir("$ab/keydir");
19
20# save arguments for later
21my $operation = shift || 'list';
22my $invitekeyid = shift || '';
23$invitekeyid and $invitekeyid !~ /^[-0-9a-z_]+@[-0-9a-z_]+$/i and die "invalid keyid $invitekeyid\n";
24my ($invited, $keyid) = split /@/, $invitekeyid;
25
26# get the actual userid and keytype
27my $gl_user = $ENV{GL_USER};
28die "This function is reserved for actual users" if $gl_user =~ s/-invite-(.*)$//;
29
30# ----
31# first collect the keys
32
33my ( @invited_keys );
34
35for my $pubkey (`find . -type f -name "*.pub" | sort`) {
36 chomp($pubkey);
37 $pubkey =~ s(^./)(); # artifact of the find command
38
39 my $user = $pubkey;
40 $user =~ s(.*/)(); # foo/bar/baz.pub -> baz.pub
41 $user =~ s/(\@[^.]+)?\.pub$//; # baz.pub, baz@home.pub -> baz
42
43 if ( $user =~ m(^(zzz-marked-for-...-)?$gl_user-invite-) ) {
44 push @invited_keys, $pubkey;
45 }
46}
47
48# ----
49# list mode; just do it and exit
50sub print_keylist {
51 my ( $message, @list ) = @_;
52 return unless @list;
53 print "== $message ==\n";
54 my $count = 1;
55 for (@list) {
56 my $fp = fingerprint($_);
57 s/(zzz-marked-for-...-)?$gl_user-invite-//g;
58 s/\.pub$//;
59 s(.*/)();
60 print $count++ . ": $fp : $_\n";
61 }
62}
63if ( $operation eq 'list' ) {
64 print "you have the following invited keys:\n";
65 print_keylist( "keys for invited persons", @invited_keys );
66 print "\n\n";
67 exit;
68}
69
70# ----
71# please see docs for details on how a user interacts with this
72
73die "valid operations: add, del\n" unless $operation =~ /^(add|del)$/;
74
75if ( $operation eq 'add' ) {
76 print STDERR "please supply the new key on STDIN. (I recommend you
77 don't try to do this interactively, but use a pipe)\n";
78 kf_add( $gl_user, $invited, $keyid, safe_stdin() );
79} elsif ( $operation eq 'del' ) {
80 kf_del( $gl_user, $invited, $keyid );
81}
82
83exit;
84
85# ----
86
87# make a temp clone and switch to it
88our $TEMPDIR;
89BEGIN { $TEMPDIR = `mktemp -d -t tmp.XXXXXXXXXX`; }
90END { `rm -rf $TEMPDIR`; }
91
92sub cd_temp_clone {
93 chomp($TEMPDIR);
94 hushed_git( "clone", "$rb/gitolite-admin.git", "$TEMPDIR" );
95 chdir($TEMPDIR);
96 my $hostname = `hostname`; chomp($hostname);
97 hushed_git( "config", "--get", "user.email" ) and hushed_git( "config", "user.email", $ENV{USER} . "@" . $hostname );
98 hushed_git( "config", "--get", "user.name" ) and hushed_git( "config", "user.name", "$ENV{USER} on $hostname" );
99}
100
101sub fingerprint {
102 my ($fp, $output) = ssh_fingerprint_file(shift);
103 # Do not print the output of $output to an untrusted destination.
104 die "does not seem to be a valid pubkey\n" unless $fp;
105 return $fp;
106}
107
108sub safe_stdin {
109 # read one line from STDIN
110 my $data;
111 my $ret = read STDIN, $data, 4096;
112 # current pubkeys are approx 400 bytes so we go a little overboard
113 die "could not read pubkey data" . ( defined($ret) ? "" : ": $!" ) . "\n" unless $ret;
114 die "pubkey data seems to have more than one line\n" if $data =~ /\n./;
115 return $data;
116}
117
118sub hushed_git {
119 local (*STDOUT) = \*STDOUT;
120 local (*STDERR) = \*STDERR;
121 open( STDOUT, ">", "/dev/null" );
122 open( STDERR, ">", "/dev/null" );
123 system( "git", @_ );
124}
125
126sub highlander {
127 # there can be only one
128 my ( $keyid, $die_if_empty, @a ) = @_;
129 # too many?
130 if ( @a > 1 ) {
131 print STDERR "
132more than one key satisfies this condition, and I can't deal with that!
133The keys are:
134
135";
136 print STDERR "\t" . join( "\n\t", @a ), "\n\n";
137 exit 1;
138 }
139 # too few?
140 die "no keys with " . ( $keyid || "empty" ) . " keyid found\n" if $die_if_empty and not @a;
141
142 return @a;
143}
144
145sub kf_add {
146 my ( $gl_user, $invited, $keyid, $keymaterial ) = @_;
147
148 # add a new "invited" key for $gl_user.
149 cd_temp_clone();
150 chdir("keydir");
151
152 mkdir("invited");
153 _print( "invited/$gl_user-invite-$invited\@$keyid.pub", $keymaterial );
154 hushed_git( "add", "." ) and die "git add failed\n";
155 my $fp = fingerprint("invited/$gl_user-invite-$invited\@$keyid.pub");
156 hushed_git( "commit", "-m", "invite add $gl_user-invite-$invited\@$keyid ($fp)" ) and die "git commit failed\n";
157 system("gitolite push >/dev/null 2>/dev/null") and die "git push failed\n";
158}
159
160sub kf_del {
161 my ( $gl_user, $invited, $keyid ) = @_;
162
163 cd_temp_clone();
164 chdir("keydir");
165
166 my @pk = highlander( $keyid, 1, grep { m(^(.*/)?(zzz-marked-for-...-)?$gl_user-invite-$invited\@$keyid.pub$) } @invited_keys );
167
168 my $fp = fingerprint( $pk[0] );
169 hushed_git( "rm", $pk[0]) and die "git mv failed\n";
170 hushed_git( "commit", "-m", "invite del $pk[0] ($fp)" ) and die "git commit failed\n";
171 system("gitolite push >/dev/null 2>/dev/null") and die "git push failed\n";
172}