From 3baaa399714f45fc88e2b785a958d190cfeff797 Mon Sep 17 00:00:00 2001
From: "Kyle J. McKay"
Date: Sun, 7 Jul 2013 10:31:20 -0700
Subject: [PATCH] Support web removal of users
A confirmation code is sent similarly to editing a user, but
it is distinct so that the edit user code may not be interchanged
with the remove user code and vice versa.
After entering the correct code, the user is asked to confirm
with an additional button click after being shown the list
of projects, if any, the user will be removed from.
---
Girocco/Project.pm | 22 ++++----
Girocco/User.pm | 11 ++--
cgi/delproj.cgi | 4 +-
cgi/deluser.cgi | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++
cgi/editproj.cgi | 4 +-
cgi/edituser.cgi | 8 ++-
html/girocco.css | 39 +++++++++++++
taskd/clone.sh | 2 +-
8 files changed, 223 insertions(+), 24 deletions(-)
create mode 100755 cgi/deluser.cgi
diff --git a/Girocco/Project.pm b/Girocco/Project.pm
index eab598d..f6ccc16 100644
--- a/Girocco/Project.pm
+++ b/Girocco/Project.pm
@@ -89,7 +89,7 @@ sub _property_fget {
return $val;
}
- open P, $self->_property_path($pname) or return undef;
+ open P, '<', $self->_property_path($pname) or return undef;
my @value =
;
close P;
my $value = join('', @value); chomp $value;
@@ -153,12 +153,12 @@ sub _nofetch_path {
sub _nofetch {
my $self = shift;
my ($nofetch) = @_;
- my $np = $self->_nofetch_path;
+ my $nf = $self->_nofetch_path;
if ($nofetch) {
- open X, '>'.$np or die "nofetch failed: $!";
+ open X, '>', $nf or die "nofetch failed: $!";
close X;
} else {
- unlink $np or die "yesfetch failed: $!";
+ unlink $nf or die "yesfetch failed: $!";
}
}
@@ -182,7 +182,7 @@ sub _clonep {
my ($nofetch) = @_;
my $np = $self->_clonep_path;
if ($nofetch) {
- open X, '>'.$np or die "clonep failed: $!";
+ open X, '>', $np or die "clonep failed: $!";
close X;
} else {
unlink $np or die "clonef failed: $!";
@@ -202,14 +202,14 @@ sub _alternates_setup {
# relative path in alternates - that doesn't work recursively.
my $filename = $self->{path}.'/objects/info/alternates';
- open X, '>'.$filename or die "alternates failed: $!";
+ open X, '>', $filename or die "alternates failed: $!";
print X "$forkee_path/objects\n";
close X;
chmod 0664, $filename or warn "cannot chmod $filename: $!";
if ($Girocco::Config::httppullurl) {
$filename = $self->{path}.'/objects/info/http-alternates';
- open X, '>'.$filename or die "http-alternates failed: $!";
+ open X, '>', $filename or die "http-alternates failed: $!";
my $upfork = $forkee_name;
do { print X "$Girocco::Config::httppullurl/$upfork.git/objects\n"; } while ($upfork =~ s#/?.+?$## and $upfork); #
close X;
@@ -275,8 +275,8 @@ sub _hook_path {
sub _hook_install {
my $self = shift;
my ($name) = @_;
- open SRC, "$Girocco::Config::basedir/hooks/$name" or die "cannot open hook $name: $!";
- open DST, '>'.$self->_hook_path($name) or die "cannot open hook $name for writing: $!";
+ open SRC, '<', "$Girocco::Config::basedir/hooks/$name" or die "cannot open hook $name: $!";
+ open DST, '>', $self->_hook_path($name) or die "cannot open hook $name for writing: $!";
while () { print DST $_; }
close DST;
close SRC;
@@ -319,7 +319,7 @@ sub load {
my $class = shift;
my $name = shift || '';
- open F, jailed_file("/etc/group") or die "project load failed: $!";
+ open F, '<', jailed_file("/etc/group") or die "project load failed: $!";
while () {
chomp;
@_ = split /:+/;
@@ -727,7 +727,7 @@ sub get_full_list {
my $class = shift;
my @projects;
- open F, jailed_file("/etc/group") or die "getting project list failed: $!";
+ open F, '<', jailed_file("/etc/group") or die "getting project list failed: $!";
while () {
chomp;
@_ = split /:+/;
diff --git a/Girocco/User.pm b/Girocco/User.pm
index 5322890..1eeaad9 100644
--- a/Girocco/User.pm
+++ b/Girocco/User.pm
@@ -99,7 +99,7 @@ sub _sshkey_path {
sub _sshkey_load {
my $self = shift;
- open F, "<".jailed_file($self->_sshkey_path) or die "sshkey load failed: $!";
+ open F, '<', jailed_file($self->_sshkey_path) or die "sshkey load failed: $!";
my @keys = ();
my $auth = '';
my $authtype = '';
@@ -131,13 +131,14 @@ sub _trimkeys {
sub _sshkey_save {
my $self = shift;
$self->{keys} = _trimkeys($self->{keys} || '');
- open F, ">".jailed_file($self->_sshkey_path) or die "sshkey failed: $!";
+ open F, '>', jailed_file($self->_sshkey_path) or die "sshkey save failed: $!";
if (defined($self->{auth}) && $self->{auth}) {
my $expire = time + 24 * 3600;
my $typestr = $self->{authtype} ? uc($self->{authtype}) : 'REPO';
print F "# ${typestr}AUTH $self->{auth} $expire\n";
}
- print F $self->{keys}."\n";
+ print F $self->{keys};
+ print F "\n" if $self->{keys};
close F;
chmod 0664, jailed_file($self->_sshkey_path);
}
@@ -167,7 +168,7 @@ sub load {
my $class = shift;
my ($name) = @_;
- open F, jailed_file("/etc/passwd") or die "user load failed: $!";
+ open F, '<', jailed_file("/etc/passwd") or die "user load failed: $!";
while () {
chomp;
@_ = split /:/;
@@ -193,7 +194,7 @@ sub load_by_uid {
my $class = shift;
my ($uid) = @_;
- open F, jailed_file("/etc/passwd") or die "user load failed: $!";
+ open F, '<', jailed_file("/etc/passwd") or die "user load failed: $!";
while () {
chomp;
@_ = split /:/;
diff --git a/cgi/delproj.cgi b/cgi/delproj.cgi
index 161207c..f903364 100755
--- a/cgi/delproj.cgi
+++ b/cgi/delproj.cgi
@@ -76,7 +76,7 @@ you have used it.
EOT
@@ -100,7 +100,7 @@ EOT
EOT
diff --git a/cgi/deluser.cgi b/cgi/deluser.cgi
new file mode 100755
index 0000000..8ff55d1
--- /dev/null
+++ b/cgi/deluser.cgi
@@ -0,0 +1,157 @@
+#!/usr/bin/perl
+
+# deluser.cgi -- support for user deletion via web
+# Copyright (c) 2013 Kyle J. McKay. All rights reserved.
+# Portions (c) Petr Baudis and (c) Jan Krueger
+# License GPLv2+: GNU GPL version 2 or later.
+# www.gnu.org/licenses/gpl-2.0.html
+# This is free software: you are free to change and redistribute it.
+# There is NO WARRANTY, to the extent permitted by law.
+
+use strict;
+use warnings;
+
+use lib ".";
+use Girocco::CGI;
+use Girocco::Config;
+use Girocco::User;
+use Girocco::Util;
+
+my $gcgi = Girocco::CGI->new('User Removal');
+my $cgi = $gcgi->cgi;
+
+unless ($Girocco::Config::manage_users) {
+ print "
+
+
+EOT
+}
+
+if ($cgi->param('name')) {
+ # submitted, let's see
+ # FIXME: racy, do a lock
+ my $name = $gcgi->wparam('name');
+ (Girocco::User::valid_name($name)
+ and Girocco::User::does_exist($name))
+ or $gcgi->err("Username is not registered.");
+
+ $gcgi->err_check and exit;
+
+ my $user;
+ ($user = Girocco::User->load($name)) && valid_email($user->{email})
+ or $gcgi->err("Username may not be removed.");
+
+ $gcgi->err_check and exit;
+
+ if (!$cgi->param('auth')) {
+ my $auth = $user->gen_auth('DEL');
+
+ # Send auth mail
+ open(MAIL, '|-', '/usr/bin/mail', '-s', "[$Girocco::Config::name] Account removal authorization", $user->{email}) or
+ die "Sorry, could not send authorization code: $!";
+ print MAIL <You should shortly receive an e-mail containing an authorization code.
+ Please enter this code below to remove your account.
+ The code will expire in 24 hours or after you have used it.
";
+ _auth_form($name, "'Login'");
+ exit;
+ } else {
+ $user->{auth} && $user->{authtype} eq 'DEL' or do {
+ print "There currently isn't any authorization code filed under your account. ".
+ "Please generate one.";
+ exit;
+ };
+
+ my $auth = $gcgi->wparam('auth');
+ if ($auth ne $user->{auth}) {
+ print '
Invalid authorization code, please re-enter or ".
+ "generate a new one.
';
+ _auth_form($name, "'Login'");
+ exit;
+ }
+
+ my $y0 = $gcgi->wparam('y0') || '';
+ my $conf = $gcgi->wparam('confirm') || '';
+ if ($y0 ne 'Remove user account' || $conf ne $user->{name}) {
+ my $blurb1 = '.';
+ my $projectsinfo = '';
+ my @projects = $user->get_projects;
+ if (@projects) {
+ $blurb1 = ' and from the following projects:';
+ $projectsinfo = <
Project
Description
+EOT
+ foreach (@projects) {
+ if (Girocco::Project::does_exist($_)) {
+ my $proj = Girocco::Project->load($_);
+ $projectsinfo .= <
@{[CGI::escapeHTML($proj->{name})]}
@{[CGI::escapeHTML($proj->{desc})]}
+EOT
+ }
+ }
+ $projectsinfo .= <
+EOT
+ }
+ print <Please confirm that you are going to remove user account '$user->{name}'
+from the site$blurb1$projectsinfo
+
+EOT
+ exit;
+ }
+
+ $user->remove;
+ print "
User account successfully removed. Have a nice day.
\n";
+ exit;
+ }
+}
+
+print <Here you can request an authorization code to remove your user account.
+
+
Please enter your username below;
+we will send you an email with an authorization code
+and further instructions.
+
+
+EOT
diff --git a/cgi/editproj.cgi b/cgi/editproj.cgi
index 28279f8..b0a232b 100755
--- a/cgi/editproj.cgi
+++ b/cgi/editproj.cgi
@@ -89,9 +89,9 @@ You may
request an authorization code in order
to remove this project from the site.
EOT
- }
+ }
print <+ button to enable access for more than a single user at a time.
+
Use the + button to enable access for more than a single user at a time.
EOT
}
diff --git a/cgi/edituser.cgi b/cgi/edituser.cgi
index 443dd00..ffb89fa 100755
--- a/cgi/edituser.cgi
+++ b/cgi/edituser.cgi
@@ -32,7 +32,7 @@ sub _auth_form {
$fields = '' if (!$fields);
my $auth = shift;
my $authtag = ($auth ? qq() :
- qq(
Authorization code:
));
+ qq(
Authorization code:
));
print <
@@ -182,8 +182,10 @@ my $blurb2 = '';
$blurb2 = ' and download https push user authentication certificate(s)'
if $Girocco::Config::httpspushurl;
print <Here you can update the email and public SSH key(s) associated with your user account$blurb2.
-These public SSH key(s) are required for you to push to projects.
+