From 3177b1f959f4ee04c12761e51fa22dd9499442b8 Mon Sep 17 00:00:00 2001 From: "Kyle J. McKay" Date: Sun, 14 Feb 2021 17:41:35 -0700 Subject: [PATCH] various: prepare for use of timed tokens Add a new routine to easily fetch the key for a token category. Add new config items to indicate which project fields require a validated password even to just view and how long it's valid. Create new token keys at install time if they do not exist. Signed-off-by: Kyle J. McKay --- Girocco/Config.pm | 13 ++++++++++++- Girocco/Util.pm | 26 +++++++++++++++++++++++++- Girocco/Validator.pm | 7 +++++++ install.sh | 21 +++++++++++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/Girocco/Config.pm b/Girocco/Config.pm index 08e559f..049bb00 100644 --- a/Girocco/Config.pm +++ b/Girocco/Config.pm @@ -245,6 +245,17 @@ our $project_owners = 'email'; # be edited does work and the value is saved, the value is totally ignored by Girocco our @project_fields = qw(cleanmirror homepage shortdesc README notifymail reverseorder summaryonly notifytag notifyjson); +# Which project fields to protect -- they will first require the project +# password to be entered before they can even be viewed on the editproj page +our $protect_fields = {map({$_ => 1} qw(notifymail notifytag notifyjson))}; + +# Registration/Edit expiration time +# The registration form must be completed within this amount of time +# or it will time out and require starting over. The project edit page +# must be submitted within this amount of time or it will time out and +# require starting over. +our $project_edit_timeout = 1800; # 30 minutes + # Minimal number of seconds to pass between two updates of a project. our $min_mirror_interval = 3600; # 1 hour @@ -410,7 +421,7 @@ our $basedir = '/home/repo/repomgr'; # Path where the automatically generated non-user certificates will be stored # (The per-user certificates are always stored in $chroot/etc/sshcerts/) # This is preserved by each make install and MUST NOT be under $basedir! -# Not used unless $httpspushurl is defined +# The secrets used to generate TimedTokens are also stored in here. # MUST be an absolute path our $certsdir = '/home/repo/certs'; diff --git a/Girocco/Util.pm b/Girocco/Util.pm index f5713f7..62240ec 100644 --- a/Girocco/Util.pm +++ b/Girocco/Util.pm @@ -26,7 +26,7 @@ BEGIN { clean_email_multi read_HEAD_symref read_config_file read_config_file_hash is_git_dir git_bool util_path is_shellish read_HEAD_ref git_add_config to_json - json_bool from_json ref_indicator); + json_bool from_json ref_indicator get_token_key); } BEGIN {require "Girocco/extra/capture_command.pl"} @@ -1396,4 +1396,28 @@ sub ref_indicator { return wantarray ? ($ans, 1) : $ans; } +# return the token key to use for the passed in category +# if there is no such token or it cannot be read or is invalid +# then silently return undef +# category names must currently be 32 or fewer alphanumeric +# characters where the first must be an alpha char +# $_[0] -> category name +sub get_token_key { + my $cname = shift; + defined($cname) or return undef; + $cname = lc($cname); + $cname =~ /^([a-z][a-z0-9]{0,31})$/ or return undef; + $cname = $1; + my $tf = $Girocco::Config::certsdir . "/tokenkeys/$cname.tky"; + -e $tf && -f _ && -r _ && -s _ or return undef; + my $fh; + open $fh, '<', $tf or return undef; + my $tk = <$fh>; + close $fh; + defined($tk) or return undef; + chomp($tk); + $tk =~ /^([A-Za-z0-9_-]{48})$/ or return undef; + return $1; +} + 1; diff --git a/Girocco/Validator.pm b/Girocco/Validator.pm index f3c6f0d..43dbec2 100644 --- a/Girocco/Validator.pm +++ b/Girocco/Validator.pm @@ -54,6 +54,13 @@ $disable_jailsetup = $disable_jailsetup ? 1 : ''; $notify_single_level = $notify_single_level ? 1 : ''; $fetch_stash_refs = $fetch_stash_refs ? 1 : ''; !$mob || $mob eq 'mob' or die "Girocco::Config: \$mob must be undef (or '') or 'mob'"; +!defined($protect_fields) || ref($protect_fields) eq 'HASH' or + die "Girocco::Config: \$protect_fields must be a HASH ref or undefined"; +ref($protect_fields) eq 'HASH' or $protect_fields = {}; +$project_edit_timeout =~ /^[1-9][0-9]*$/ or + die "Girocco::Config: \$project_edit_timeout must be a positive integer"; +5 <= $project_edit_timeout && $project_edit_timeout <= 86400 or + die "Girocco::Config: \$project_edit_timeout seems unreasonable: $project_edit_timeout"; !$min_key_length || $min_key_length =~ /^[1-9][0-9]*$/ or die "Girocco::Config: \$min_key_length must be undef or numeric"; !defined($max_readme_size) || $max_readme_size =~ /^[0-9]+$/ or diff --git a/install.sh b/install.sh index 4a70841..79e6eab 100755 --- a/install.sh +++ b/install.sh @@ -1056,6 +1056,27 @@ cp robots.txt "$webroot" cat gitweb/gitweb.css >>"$webroot"/gitweb.css +echo "*** Setting up token keys..." +mkdir -p "$cfg_certsdir/tokenkeys" +"$var_perl_bin" -I"$PWD" -M$GIROCCO_CONF -MGirocco::Validator -MGirocco::Util -MGirocco::TimedToken -e ' + my $basedir; $Girocco::Config::certsdir =~ /^(.+)$/ and $basedir = "$1/tokenkeys"; + -d "$basedir" && -w _ or die "no such writable directory: \"$basedir\"\n"; + foreach (qw(projedit)) { + my $tk = get_token_key($_); + if (!defined($tk)) { + my $tf = "$basedir/$_.tky"; + $tk = create_token_secret(); + my $fh; + open $fh, ">", "$tf" or + die "unable to open \"$tf\" for writing: $!\n"; + printf $fh "%s\n", $tk; + close $fh or die "error closing \"$tf\": $!\n"; + printf "%s\n", "Created new $_ token secret"; + } + } +' + + if [ -n "$cfg_httpspushurl" ]; then echo "*** Setting up SSL certificates..." openssl="${var_openssl_bin:-openssl}" -- 2.11.4.GIT