From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

#!/usr/bin/perl -w
use strict;
die 'Need $HOME to be set!' unless exists($ENV{HOME});
my $config = SReview::Config::Common::setup;
my $eventname = $config->get('event');
my $action = "add";
my $oknodo = 0;
my $help = 0;
my $keyfile = undef;
my $bindir = $ENV{HOME} . "/bin";
GetOptions(
"event|e=s" => \$eventname,
"action|a=s" => \$action,
"help" => \$help,
"oknodo|o" => \$oknodo,
"file|f=s" => \$keyfile,
) or pod2usage("command line invalid");
=head1 NAME
sreview-keys - manage keys in SReview's C<authorized_keys> file.
=head1 SYNOPSIS
sreview-keys --event="event name" --action="add" --file=./id_rsa.pub
sreview-keys -a "remove" --file=./id_rsa.pub
=head1 DESCRIPTION
sreview-keys is a simple tool to manage keys in an C<authorized_keys>
file so that when you run C<rsync> to sync input data to the SReview
master server, the files are written to that event's own input directory
(and not elsewhere).
The default event name is taken from the SReview configuration file (see
L<sreview-config>, or it can be overridden with C<--event> (alias:
C<-e>).
The default action is to add a key; to remove one, either edit the file,
or use the C<--action=remove> (alias: C<-a remove>) option.
=cut
if($help) {
pod2usage(0);
}
if(!defined($keyfile)) {
pod2usage("key file not specified");
}
if($action ne "add" && $action ne "remove") {
print STDERR "Unknown action: $action\n";
exit 1;
}
my $event = SReview::Model::Event->new(config => $config, name => $eventname);
my $akf = Net::SSH::AuthorizedKeysFile->new();
my $file = $config->get('authkeyfile');
$akf->read($file);
open KEY, "<", $keyfile;
my $mkey = "";
while(<KEY>) {
chomp;
$mkey .= $_;
}
close KEY;
$mkey = Net::SSH::AuthorizedKey->parse($mkey);
my @newkeys = ();
foreach my $key($akf->keys()) {
if($key->fingerprint() eq $mkey->fingerprint()) {
if($action eq "add") {
if(!$oknodo) {
print STDERR "The provided key already exists in the file! Please remove it first\n";
exit 1;
} else {
print "Key already added, ignoring\n";
exit 0;
}
} else {
# don't add to @mkeys
next;
}
}
push @newkeys, $key;
}
if($action eq "add") {
if(! -x "$bindir/rrsync") {
print STDERR "E: please install rrsync as $bindir/rrsync, and make sure it's executable (hint: /usr/share/doc/rsync/scripts/rrsync.gz)";
exit 1;
}
my $iglob = $config->get('inputglob');
my @input = split('/', $iglob);
my @dirs = ();
foreach my $in(@input) {
if($in =~ /\*/) {
last;
}
push @dirs, $in;
}
$mkey->option("command", "$bindir/rrsync '" . join('/', @dirs, $event->inputdir) . "'", 1);
$mkey->option("no-agent-forwarding", 1, 1);
$mkey->option("no-port-forwarding", 1, 1);
$mkey->option("no-pty", 1, 1);
$mkey->option("no-user-rc", 1, 1);
$mkey->option("no-X11-forwarding", 1, 1);
push @newkeys, $mkey;
}
if(!defined($file)) {
$file = $akf->path_locate;
}
$akf = Net::SSH::AuthorizedKeysFile->new(keys => \@newkeys, file => $file);
$akf->save();