mourningdove/cgi-bin/LJ/Console/Command/PrivPackage.pm

195 lines
7.3 KiB
Perl
Raw Permalink Normal View History

2026-05-24 01:03:05 +00:00
# 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;