195 lines
7.3 KiB
Perl
195 lines
7.3 KiB
Perl
|
|
# This code was forked from the LiveJournal project owned and operated
|
||
|
|
# by Live Journal, Inc. The code has been modified and expanded by
|
||
|
|
# Dreamwidth Studios, LLC. These files were originally licensed under
|
||
|
|
# the terms of the license supplied by Live Journal, Inc, which can
|
||
|
|
# currently be found at:
|
||
|
|
#
|
||
|
|
# http://code.livejournal.org/trac/livejournal/browser/trunk/LICENSE-LiveJournal.txt
|
||
|
|
#
|
||
|
|
# In accordance with the original license, this code and all its
|
||
|
|
# modifications are provided under the GNU General Public License.
|
||
|
|
# A copy of that license can be found in the LICENSE file included as
|
||
|
|
# part of this distribution.
|
||
|
|
|
||
|
|
package LJ::Console::Command::PrivPackage;
|
||
|
|
|
||
|
|
use strict;
|
||
|
|
use base qw(LJ::Console::Command);
|
||
|
|
use Carp qw(croak);
|
||
|
|
|
||
|
|
sub cmd { "priv_package" }
|
||
|
|
|
||
|
|
sub desc {
|
||
|
|
"Manage packages of admin privs. Basic workflow: priv_package create mypkg \"Test Package\", priv_package add mypkg admin:*, priv_package list. To actually grant a package to someone, priv grant #mypkg username. Works for revoke as well. Requires priv: admin.";
|
||
|
|
}
|
||
|
|
|
||
|
|
sub args_desc {
|
||
|
|
[
|
||
|
|
'command' => 'One of "list", "create", "add", "remove", "delete".',
|
||
|
|
'package' => 'The package to operate on. Use a short name.',
|
||
|
|
'arg' =>
|
||
|
|
'If command is "list", no argument to see all packages, or provide a package to see the privs inside. For "create" and "delete" of a package, no argument. For "add" and "remove", arg is the privilege being granted in "privname:privarg" format.',
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
sub usage { '<command> [ <package> [ <arg> ] ]' }
|
||
|
|
|
||
|
|
sub can_execute {
|
||
|
|
my $remote = LJ::get_remote();
|
||
|
|
return $remote && $remote->has_priv("admin");
|
||
|
|
}
|
||
|
|
|
||
|
|
sub execute {
|
||
|
|
my ( $self, $cmd, $pkg, $arg, @args ) = @_;
|
||
|
|
|
||
|
|
return $self->error("This command takes one, two, or three arguments. Consult the reference.")
|
||
|
|
unless $cmd && scalar(@args) == 0;
|
||
|
|
|
||
|
|
return $self->error("Invalid command. Consult the reference.")
|
||
|
|
unless $cmd =~ /^(?:list|create|add|remove|delete)$/;
|
||
|
|
|
||
|
|
return $self->error("'$cmd' requires an argument.")
|
||
|
|
if $cmd =~ /^(?:add|remove)$/ && !$arg;
|
||
|
|
|
||
|
|
$pkg =~ s/^#//; # just in case they put a # on it
|
||
|
|
|
||
|
|
my $dbh = LJ::get_db_writer();
|
||
|
|
my $remote = LJ::get_remote();
|
||
|
|
my ( $pkgid, $cpkg ) =
|
||
|
|
$dbh->selectrow_array( 'SELECT pkgid, name FROM priv_packages WHERE name = ?', undef,
|
||
|
|
$pkg );
|
||
|
|
return $self->error( "Database error: " . $dbh->errstr )
|
||
|
|
if $dbh->err;
|
||
|
|
|
||
|
|
# canonical package name is "#" plus whatever is in the db
|
||
|
|
$cpkg = defined $cpkg ? "#$cpkg" : undef;
|
||
|
|
|
||
|
|
# list created packages, or contents of one
|
||
|
|
if ( $cmd eq 'list' ) {
|
||
|
|
if ( $pkg && $pkg ne 'all' ) {
|
||
|
|
return $self->error("Package with that name does not exist")
|
||
|
|
unless $pkgid;
|
||
|
|
|
||
|
|
my $contents = $dbh->selectall_arrayref(
|
||
|
|
'SELECT privname, privarg FROM priv_packages_content WHERE pkgid = ?',
|
||
|
|
undef, $pkgid );
|
||
|
|
return $self->error( "Database error: " . $dbh->errstr )
|
||
|
|
if $dbh->err;
|
||
|
|
|
||
|
|
$self->info("Contents of $cpkg:");
|
||
|
|
foreach my $row ( @{ $contents || [] } ) {
|
||
|
|
$self->info(" $row->[0]:$row->[1]");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
my $packages = $dbh->selectall_arrayref(
|
||
|
|
'SELECT pkgid, name, lastmoduserid, lastmodtime FROM priv_packages '
|
||
|
|
. 'ORDER BY name' );
|
||
|
|
return $self->error( "Database error: " . $dbh->errstr )
|
||
|
|
if $dbh->err;
|
||
|
|
|
||
|
|
$self->info("Available packages:");
|
||
|
|
|
||
|
|
foreach my $row ( @{ $packages || [] } ) {
|
||
|
|
my $u = LJ::load_userid( $row->[2] );
|
||
|
|
my $time = LJ::mysql_time( $row->[3] );
|
||
|
|
$self->info(
|
||
|
|
sprintf( "%5d %-20s%-20s\%s", $row->[0], $row->[1], $u->{user}, $time ) );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 1;
|
||
|
|
|
||
|
|
# create a package
|
||
|
|
}
|
||
|
|
elsif ( $cmd eq 'create' ) {
|
||
|
|
return $self->error("Package with that name already exists.")
|
||
|
|
if $pkgid;
|
||
|
|
|
||
|
|
return $self->error(
|
||
|
|
"Package names can only contain letters, numbers, underscores, hyphens, or underscores."
|
||
|
|
) unless $pkg =~ /^[a-z0-9_\-:\(\)\[\]]+$/i;
|
||
|
|
|
||
|
|
$dbh->do(
|
||
|
|
"INSERT INTO priv_packages (pkgid, name, lastmoduserid, lastmodtime) "
|
||
|
|
. "VALUES (NULL, ?, ?, UNIX_TIMESTAMP())",
|
||
|
|
undef, $pkg, $remote->id
|
||
|
|
);
|
||
|
|
|
||
|
|
return $self->print("Package '$pkg' created.");
|
||
|
|
|
||
|
|
# delete a package
|
||
|
|
}
|
||
|
|
elsif ( $cmd eq 'delete' ) {
|
||
|
|
return $self->error("Package with that name does not exist.")
|
||
|
|
unless $pkgid;
|
||
|
|
|
||
|
|
$dbh->do( "DELETE FROM priv_packages WHERE pkgid = ?", undef, $pkgid );
|
||
|
|
return $self->error( "Database error: " . $dbh->errstr )
|
||
|
|
if $dbh->err;
|
||
|
|
|
||
|
|
$dbh->do( "DELETE FROM priv_packages_content WHERE pkgid = ?", undef, $pkgid );
|
||
|
|
return $self->error( "Database error: " . $dbh->errstr )
|
||
|
|
if $dbh->err;
|
||
|
|
|
||
|
|
return $self->print("Package '$cpkg' deleted.");
|
||
|
|
|
||
|
|
# add or remove a privilige to a package
|
||
|
|
}
|
||
|
|
elsif ( $cmd eq 'add' || $cmd eq 'remove' ) {
|
||
|
|
return $self->error("Package with that name does not exist.")
|
||
|
|
unless $pkgid;
|
||
|
|
|
||
|
|
my ( $pname, $parg ) = split( /:/, $arg );
|
||
|
|
return $self->error(
|
||
|
|
"Argument must be in format of 'priv:arg' with optional arg. (The colon is required.)")
|
||
|
|
unless $pname && defined $parg;
|
||
|
|
|
||
|
|
# valid priv or not
|
||
|
|
my $valid = $dbh->selectrow_array( 'SELECT COUNT(*) FROM priv_list WHERE privcode = ?',
|
||
|
|
undef, $pname );
|
||
|
|
return $self->error("'$pname' is not a valid privilege.")
|
||
|
|
unless $valid;
|
||
|
|
|
||
|
|
# exists or not
|
||
|
|
my $exists = $dbh->selectrow_array(
|
||
|
|
'SELECT COUNT(*) FROM priv_packages_content '
|
||
|
|
. 'WHERE pkgid = ? AND privname = ? AND privarg = ?',
|
||
|
|
undef, $pkgid, $pname, $parg
|
||
|
|
);
|
||
|
|
return $self->error( "Database error: " . $dbh->errstr )
|
||
|
|
if $dbh->err;
|
||
|
|
|
||
|
|
if ( $cmd eq 'add' ) {
|
||
|
|
return $self->error("Privilege already exists in package.")
|
||
|
|
if $exists;
|
||
|
|
$dbh->do(
|
||
|
|
"INSERT INTO priv_packages_content (pkgid, privname, privarg) VALUES (?, ?, ?)",
|
||
|
|
undef, $pkgid, $pname, $parg );
|
||
|
|
return $self->error( "Database error: " . $dbh->errstr )
|
||
|
|
if $dbh->err;
|
||
|
|
$dbh->do(
|
||
|
|
"UPDATE priv_packages SET lastmoduserid = ?, lastmodtime = UNIX_TIMESTAMP() WHERE pkgid = ?",
|
||
|
|
undef, $remote->id, $pkgid
|
||
|
|
);
|
||
|
|
return $self->print("Privilege ($pname:$parg) added to package $cpkg.");
|
||
|
|
}
|
||
|
|
else { # a removal
|
||
|
|
return $self->error("Privilege does not exist in package.")
|
||
|
|
unless $exists;
|
||
|
|
$dbh->do(
|
||
|
|
"DELETE FROM priv_packages_content WHERE pkgid = ? AND privname = ? AND privarg = ?",
|
||
|
|
undef, $pkgid, $pname, $parg
|
||
|
|
);
|
||
|
|
return $self->error( "Database error: " . $dbh->errstr )
|
||
|
|
if $dbh->err;
|
||
|
|
$dbh->do(
|
||
|
|
"UPDATE priv_packages SET lastmoduserid = ?, lastmodtime = UNIX_TIMESTAMP() WHERE pkgid = ?",
|
||
|
|
undef, $remote->id, $pkgid
|
||
|
|
);
|
||
|
|
return $self->print("Privilege ($pname:$parg) removed from package $cpkg.");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
1;
|